get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/633517/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 633517,
    "url": "http://patchwork.ozlabs.org/api/patches/633517/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/skiboot/patch/1465535032-26749-14-git-send-email-gwshan@linux.vnet.ibm.com/",
    "project": {
        "id": 44,
        "url": "http://patchwork.ozlabs.org/api/projects/44/?format=api",
        "name": "skiboot firmware development",
        "link_name": "skiboot",
        "list_id": "skiboot.lists.ozlabs.org",
        "list_email": "skiboot@lists.ozlabs.org",
        "web_url": "http://github.com/open-power/skiboot",
        "scm_url": "http://github.com/open-power/skiboot",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1465535032-26749-14-git-send-email-gwshan@linux.vnet.ibm.com>",
    "list_archive_url": null,
    "date": "2016-06-10T05:03:42",
    "name": "[v12,13/23] core/pci: Support PCI slot",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "2e2da8668750ee9359d6dab080c4a82e61d1d90d",
    "submitter": {
        "id": 63923,
        "url": "http://patchwork.ozlabs.org/api/people/63923/?format=api",
        "name": "Gavin Shan",
        "email": "gwshan@linux.vnet.ibm.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/skiboot/patch/1465535032-26749-14-git-send-email-gwshan@linux.vnet.ibm.com/mbox/",
    "series": [],
    "comments": "http://patchwork.ozlabs.org/api/patches/633517/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/633517/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "skiboot@lists.ozlabs.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@bilbo.ozlabs.org",
            "skiboot@lists.ozlabs.org"
        ],
        "Received": [
            "from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3rQqt60Hb0z9sD3\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Jun 2016 15:07:26 +1000 (AEST)",
            "from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3rQqt562fLzDqd0\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Jun 2016 15:07:25 +1000 (AEST)",
            "from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com\n\t[148.163.158.5])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 3rQqrC0BhbzDqNj\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:46 +1000 (AEST)",
            "from pps.filterd (m0098416.ppops.net [127.0.0.1])\n\tby mx0b-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id\n\tu5A53qQ4100561\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 01:05:44 -0400",
            "from e23smtp02.au.ibm.com (e23smtp02.au.ibm.com [202.81.31.144])\n\tby mx0b-001b2d01.pphosted.com with ESMTP id 23fm51jyhn-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 01:05:44 -0400",
            "from localhost\n\tby e23smtp02.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <skiboot@lists.ozlabs.org> from <gwshan@linux.vnet.ibm.com>;\n\tFri, 10 Jun 2016 15:05:40 +1000",
            "from d23dlp02.au.ibm.com (202.81.31.213)\n\tby e23smtp02.au.ibm.com (202.81.31.208) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tFri, 10 Jun 2016 15:05:31 +1000",
            "from d23relay08.au.ibm.com (d23relay08.au.ibm.com [9.185.71.33])\n\tby d23dlp02.au.ibm.com (Postfix) with ESMTP id B0F722BB0061\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:20 +1000 (EST)",
            "from d23av05.au.ibm.com (d23av05.au.ibm.com [9.190.234.119])\n\tby d23relay08.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id\n\tu5A555Lk58982428\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:05 +1000",
            "from d23av05.au.ibm.com (localhost [127.0.0.1])\n\tby d23av05.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id\n\tu5A54xDW024791\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:00 +1000",
            "from ozlabs.au.ibm.com (ozlabs.au.ibm.com [9.192.253.14])\n\tby d23av05.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id\n\tu5A54xWc024650; Fri, 10 Jun 2016 15:04:59 +1000",
            "from bran.ozlabs.ibm.com (haven.au.ibm.com [9.192.254.114])\n\tby ozlabs.au.ibm.com (Postfix) with ESMTP id 20F18A01E6;\n\tFri, 10 Jun 2016 15:03:58 +1000 (AEST)",
            "from gwshan (shangw.ozlabs.ibm.com [10.61.2.199])\n\tby bran.ozlabs.ibm.com (Postfix) with ESMTP id 1FD25E3B1A;\n\tFri, 10 Jun 2016 15:03:58 +1000 (AEST)",
            "by gwshan (Postfix, from userid 1000)\n\tid 05D87942CA3; Fri, 10 Jun 2016 15:03:57 +1000 (AEST)"
        ],
        "X-IBM-Helo": "d23dlp02.au.ibm.com",
        "X-IBM-MailFrom": "gwshan@linux.vnet.ibm.com",
        "X-IBM-RcptTo": "skiboot@lists.ozlabs.org",
        "From": "Gavin Shan <gwshan@linux.vnet.ibm.com>",
        "To": "skiboot@lists.ozlabs.org",
        "Date": "Fri, 10 Jun 2016 15:03:42 +1000",
        "X-Mailer": "git-send-email 2.1.0",
        "In-Reply-To": "<1465535032-26749-1-git-send-email-gwshan@linux.vnet.ibm.com>",
        "References": "<1465535032-26749-1-git-send-email-gwshan@linux.vnet.ibm.com>",
        "X-TM-AS-MML": "disable",
        "X-Content-Scanned": "Fidelis XPS MAILER",
        "x-cbid": "16061005-0004-0000-0000-0000016C9182",
        "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused",
        "x-cbparentid": "16061005-0005-0000-0000-0000080CBB79",
        "Message-Id": "<1465535032-26749-14-git-send-email-gwshan@linux.vnet.ibm.com>",
        "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2016-06-10_04:, , signatures=0",
        "X-Proofpoint-Spam-Details": "rule=outbound_notspam policy=outbound score=0\n\tspamscore=0 suspectscore=4\n\tmalwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam\n\tadjust=0 reason=mlx scancount=1 engine=8.0.1-1604210000\n\tdefinitions=main-1606100058",
        "Subject": "[Skiboot] [PATCH v12 13/23] core/pci: Support PCI slot",
        "X-BeenThere": "skiboot@lists.ozlabs.org",
        "X-Mailman-Version": "2.1.22",
        "Precedence": "list",
        "List-Id": "Mailing list for skiboot development <skiboot.lists.ozlabs.org>",
        "List-Unsubscribe": "<https://lists.ozlabs.org/options/skiboot>,\n\t<mailto:skiboot-request@lists.ozlabs.org?subject=unsubscribe>",
        "List-Archive": "<http://lists.ozlabs.org/pipermail/skiboot/>",
        "List-Post": "<mailto:skiboot@lists.ozlabs.org>",
        "List-Help": "<mailto:skiboot-request@lists.ozlabs.org?subject=help>",
        "List-Subscribe": "<https://lists.ozlabs.org/listinfo/skiboot>,\n\t<mailto:skiboot-request@lists.ozlabs.org?subject=subscribe>",
        "Cc": "alistair@popple.id.au",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org",
        "Sender": "\"Skiboot\"\n\t<skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>"
    },
    "content": "Every PCIE bridge port or PHB is expected to be bound with PCI slot\n, to which various PCI slot's functionalities are attached (e.g. power,\nlink, reset). This supports PCI slot:\n\n   * PCI slot is reprsented by \"struct pci_slot\".\n   * \"struct pci_slot_ops\" represents the functions supported on the\n     PCI slot. It's initialized by PCI slot core at the beginning and\n     allowed to be overrided by platform partially or completely.\n   * On PCI hot plugging event, the PCI devices behind the slot are\n     enumarated. Device sub-tree is populated and sent to OS by OPAL\n     message.\n   * On PCI hot unplugging event, the PCI devices behind the slot are\n     destroyed. Device sub-tree is removed and the slot is powered off.\n\nSigned-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>\n---\n core/Makefile.inc         |   4 +-\n core/pci-slot.c           | 206 +++++++++++++++++++++\n core/pci.c                |  77 +++++---\n core/pcie-slot.c          | 452 ++++++++++++++++++++++++++++++++++++++++++++++\n include/opal-api.h        |  10 +\n include/pci-slot.h        | 255 ++++++++++++++++++++++++++\n include/pci.h             |  66 ++-----\n include/platform.h        |   1 +\n platforms/ibm-fsp/lxvpd.c |   1 +\n 9 files changed, 992 insertions(+), 80 deletions(-)\n create mode 100644 core/pci-slot.c\n create mode 100644 core/pcie-slot.c\n create mode 100644 include/pci-slot.h",
    "diff": "diff --git a/core/Makefile.inc b/core/Makefile.inc\nindex 5af0d7c..13b287c 100644\n--- a/core/Makefile.inc\n+++ b/core/Makefile.inc\n@@ -3,8 +3,8 @@\n SUBDIRS += core\n CORE_OBJS = relocate.o console.o stack.o init.o chip.o mem_region.o\n CORE_OBJS += malloc.o lock.o cpu.o utils.o fdt.o opal.o interrupts.o\n-CORE_OBJS += timebase.o opal-msg.o pci.o pci-opal.o fast-reboot.o\n-CORE_OBJS += device.o exceptions.o trace.o affinity.o vpd.o\n+CORE_OBJS += timebase.o opal-msg.o pci.o pci-slot.o pcie-slot.o pci-opal.o\n+CORE_OBJS += fast-reboot.o device.o exceptions.o trace.o affinity.o vpd.o\n CORE_OBJS += hostservices.o platform.o nvram.o nvram-format.o hmi.o\n CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o\n CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o\ndiff --git a/core/pci-slot.c b/core/pci-slot.c\nnew file mode 100644\nindex 0000000..8735598\n--- /dev/null\n+++ b/core/pci-slot.c\n@@ -0,0 +1,206 @@\n+/* Copyright 2013-2016 IBM Corp.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n+ * implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include <skiboot.h>\n+#include <opal-msg.h>\n+#include <pci-cfg.h>\n+#include <pci.h>\n+#include <pci-slot.h>\n+\n+/* Debugging options */\n+#define PCI_SLOT_PREFIX\t\"PCI-SLOT-%016llx \"\n+#define PCI_SLOT_DBG(s, fmt, a...)\t\t \\\n+\tprlog(PR_DEBUG, PCI_SLOT_PREFIX fmt, (s)->id, ##a)\n+\n+static void pci_slot_prepare_link_change(struct pci_slot *slot, bool up)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t aercap, mask;\n+\n+\t/*\n+\t * Mask the link down and receiver error before the link becomes\n+\t * down. Otherwise, unmask the errors when the link is up.\n+\t */\n+\tif (pci_has_cap(pd, PCIECAP_ID_AER, true)) {\n+\t\taercap = pci_cap(pd, PCIECAP_ID_AER, true);\n+\n+\t\t/* Link down error */\n+\t\tpci_cfg_read32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_MASK,\n+\t\t\t       &mask);\n+\t\tif (up)\n+\t\t\tmask &= ~PCIECAP_AER_UE_MASK_SURPRISE_DOWN;\n+\t\telse\n+\t\t\tmask |= PCIECAP_AER_UE_MASK_SURPRISE_DOWN;\n+\t\tpci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_MASK,\n+\t\t\t\tmask);\n+\n+\t\t/* Receiver error */\n+\t\tpci_cfg_read32(phb, pd->bdfn, aercap + PCIECAP_AER_CE_MASK,\n+\t\t\t       &mask);\n+\t\tif (up)\n+\t\t\tmask &= ~PCIECAP_AER_CE_RECVR_ERR;\n+\t\telse\n+\t\t\tmask |= PCIECAP_AER_CE_RECVR_ERR;\n+\t\tpci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_CE_MASK,\n+\t\t\t\tmask);\n+\t}\n+\n+\t/*\n+\t * We're coming back from reset. We need restore bus ranges\n+\t * and reinitialize the affected bridges and devices.\n+\t */\n+\tif (up) {\n+\t\tpci_restore_bridge_buses(phb, pd);\n+\t\tif (phb->ops->device_init)\n+\t\t\tpci_walk_dev(phb, pd, phb->ops->device_init, NULL);\n+\t}\n+}\n+\n+static int64_t pci_slot_sm_poll(struct pci_slot *slot)\n+{\n+\tuint64_t now = mftb();\n+\tint64_t ret;\n+\n+\t/* Return remaining timeout if we're still waiting */\n+\tif (slot->delay_tgt_tb &&\n+\t    tb_compare(now, slot->delay_tgt_tb) == TB_ABEFOREB)\n+\t\treturn slot->delay_tgt_tb - now;\n+\n+\tslot->delay_tgt_tb = 0;\n+\tswitch (slot->state & PCI_SLOT_STATE_MASK) {\n+\tcase PCI_SLOT_STATE_LINK:\n+\t\tret = slot->ops.poll_link(slot);\n+\t\tbreak;\n+\tcase PCI_SLOT_STATE_HRESET:\n+\t\tret = slot->ops.hreset(slot);\n+\t\tbreak;\n+\tcase PCI_SLOT_STATE_FRESET:\n+\t\tret = slot->ops.freset(slot);\n+\t\tbreak;\n+\tcase PCI_SLOT_STATE_PFRESET:\n+\t\tret = slot->ops.pfreset(slot);\n+\t\tbreak;\n+\tcase PCI_SLOT_STATE_CRESET:\n+\t\tret = slot->ops.creset(slot);\n+\t\tbreak;\n+\tdefault:\n+\t\tprlog(PR_ERR, PCI_SLOT_PREFIX\n+\t\t      \"Invalid state %08x\\n\", slot->id, slot->state);\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\t\treturn OPAL_HARDWARE;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+void pci_slot_add_dt_properties(struct pci_slot *slot,\n+\t\t\t\tstruct dt_node *np)\n+{\n+\t/* Bail without device node */\n+\tif (!np)\n+\t\treturn;\n+\n+\tdt_add_property_cells(np, \"ibm,reset-by-firmware\", 1);\n+\tdt_add_property_cells(np, \"ibm,slot-pluggable\", slot->pluggable);\n+\tdt_add_property_cells(np, \"ibm,slot-power-ctl\", slot->power_ctl);\n+\tdt_add_property_cells(np, \"ibm,slot-power-led-ctlled\",\n+\t\t\t      slot->power_led_ctl);\n+\tdt_add_property_cells(np, \"ibm,slot-attn-led\", slot->attn_led_ctl);\n+\tdt_add_property_cells(np, \"ibm,slot-connector-type\",\n+\t\t\t      slot->connector_type);\n+\tdt_add_property_cells(np, \"ibm,slot-card-desc\", slot->card_desc);\n+\tdt_add_property_cells(np, \"ibm,slot-card-mech\", slot->card_mech);\n+\tdt_add_property_cells(np, \"ibm,slot-wired-lanes\", slot->wired_lanes);\n+\n+\tif (slot->ops.add_properties)\n+\t\tslot->ops.add_properties(slot, np);\n+}\n+\n+struct pci_slot *pci_slot_alloc(struct phb *phb,\n+\t\t\t\tstruct pci_device *pd)\n+{\n+\tstruct pci_slot *slot = NULL;\n+\n+\t/*\n+\t * The function can be used to allocate either PHB slot or normal\n+\t * one. For both cases, the @phb should be always valid.\n+\t */\n+\tif (!phb)\n+\t\treturn NULL;\n+\n+\t/*\n+\t * When @pd is NULL, we're going to create a PHB slot. Otherwise,\n+\t * a normal slot will be created. Check if the specified slot\n+\t * already exists or not.\n+\t */\n+\tslot = pd ? pd->slot : phb->slot;\n+\tif (slot) {\n+\t\tprlog(PR_ERR, PCI_SLOT_PREFIX \"Already exists\\n\", slot->id);\n+\t\treturn slot;\n+\t}\n+\n+\t/* Allocate memory chunk */\n+\tslot = zalloc(sizeof(struct pci_slot));\n+\tif (!slot) {\n+\t\tprlog(PR_ERR, \"%s: Out of memory\\n\", __func__);\n+\t\treturn NULL;\n+\t}\n+\n+\t/*\n+\t * The polling function sholdn't be overridden by individual\n+\t * platforms\n+\t */\n+\tslot->phb = phb;\n+\tslot->pd = pd;\n+\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\tslot->power_state = PCI_SLOT_POWER_ON;\n+\tslot->ops.poll = pci_slot_sm_poll;\n+\tslot->ops.prepare_link_change = pci_slot_prepare_link_change;\n+\tif (!pd) {\n+\t\tslot->id = PCI_PHB_SLOT_ID(phb);\n+\t\tphb->slot = slot;\n+\t} else {\n+\t\tslot->id = PCI_SLOT_ID(phb, pd->bdfn);\n+\t\tpd->slot = slot;\n+\t}\n+\n+\treturn slot;\n+}\n+\n+struct pci_slot *pci_slot_find(uint64_t id)\n+{\n+\tstruct phb *phb;\n+\tstruct pci_device *pd;\n+\tstruct pci_slot *slot;\n+\tuint64_t index;\n+\tuint16_t bdfn;\n+\n+\tindex = PCI_SLOT_PHB_INDEX(id);\n+\tphb = pci_get_phb(index);\n+\n+\t/* PHB slot */\n+\tif (!(id & PCI_SLOT_ID_PREFIX)) {\n+\t\tslot = phb ? phb->slot : NULL;\n+\t\treturn slot;\n+\t}\n+\n+\t/* Normal PCI slot */\n+\tbdfn = PCI_SLOT_BDFN(id);\n+\tpd = phb ? pci_find_dev(phb, bdfn) : NULL;\n+\tslot = pd ? pd->slot : NULL;\n+\treturn slot;\n+}\ndiff --git a/core/pci.c b/core/pci.c\nindex b36d5a6..d5e0b60 100644\n--- a/core/pci.c\n+++ b/core/pci.c\n@@ -18,6 +18,7 @@\n #include <cpu.h>\n #include <pci.h>\n #include <pci-cfg.h>\n+#include <pci-slot.h>\n #include <timebase.h>\n #include <device.h>\n #include <fsp.h>\n@@ -452,11 +453,33 @@ static void pci_cleanup_bridge(struct phb *phb, struct pci_device *pd)\n \tpci_cfg_write16(phb, pd->bdfn, PCI_CFG_CMD, cmd);\t\n }\n \n+/* Remove all subordinate PCI devices leading from the indicated\n+ * PCI bus. It's used to remove all PCI devices behind one PCI\n+ * slot at unplugging time\n+ */\n+void pci_remove_bus(struct phb *phb, struct list_head *list)\n+{\n+\tstruct pci_device *pd, *tmp;\n+\n+\tlist_for_each_safe(list, pd, tmp, link) {\n+\t\tpci_remove_bus(phb, &pd->children);\n+\n+\t\t/* Release device node and PCI slot */\n+\t\tif (pd->dn)\n+\t\t\tdt_free(pd->dn);\n+\t\tif (pd->slot)\n+\t\t\tfree(pd->slot);\n+\n+\t\t/* Remove from parent list and release itself */\n+\t\tlist_del(&pd->link);\n+\t\tfree(pd);\n+\t}\n+}\n \n-/* pci_scan - Perform a recursive scan of the bus at bus_number\n- *            populating the list passed as an argument. This also\n- *            performs the bus numbering, so it returns the largest\n- *            bus number that was assigned.\n+/* Perform a recursive scan of the bus at bus_number populating\n+ * the list passed as an argument. This also performs the bus\n+ * numbering, so it returns the largest bus number that was\n+ * assigned.\n  *\n  * Note: Eventually this might want to access some VPD information\n  *       in order to know what slots to scan and what not etc..\n@@ -466,9 +489,9 @@ static void pci_cleanup_bridge(struct phb *phb, struct pci_device *pd)\n  * XXX NOTE: We might also want to setup the PCIe MPS/MRSS properly\n  *           here as Linux may or may not do it\n  */\n-static uint8_t pci_scan(struct phb *phb, uint8_t bus, uint8_t max_bus,\n-\t\t\tstruct list_head *list, struct pci_device *parent,\n-\t\t\tbool scan_downstream)\n+uint8_t pci_scan_bus(struct phb *phb, uint8_t bus, uint8_t max_bus,\n+\t\t     struct list_head *list, struct pci_device *parent,\n+\t\t     bool scan_downstream)\n {\n \tstruct pci_device *pd = NULL;\n \tuint8_t dev, fn, next_bus, max_sub, save_max;\n@@ -585,8 +608,8 @@ static uint8_t pci_scan(struct phb *phb, uint8_t bus, uint8_t max_bus,\n \n \t\t/* Perform recursive scan */\n \t\tif (do_scan) {\n-\t\t\tmax_sub = pci_scan(phb, next_bus, max_bus,\n-\t\t\t\t\t   &pd->children, pd, true);\n+\t\t\tmax_sub = pci_scan_bus(phb, next_bus, max_bus,\n+\t\t\t\t\t       &pd->children, pd, true);\n \t\t} else if (!use_max) {\n \t\t\t/* XXX Empty bridge... we leave room for hotplug\n \t\t\t * slots etc.. but we should be smarter at figuring\n@@ -794,7 +817,7 @@ static void pci_scan_phb(void *data)\n \t/* Scan root port and downstream ports if applicable */\n \tPCIDBG(phb, 0, \"Scanning (upstream%s)...\\n\",\n \t       has_link ? \"+downsteam\" : \" only\");\n-\tpci_scan(phb, 0, 0xff, &phb->devices, NULL, has_link);\n+\tpci_scan_bus(phb, 0, 0xff, &phb->devices, NULL, has_link);\n \n \t/* Configure MPS (Max Payload Size) for PCIe domain */\n \tpci_walk_dev(phb, NULL, pci_get_mps, &mps);\n@@ -1320,12 +1343,12 @@ static void pci_print_summary_line(struct phb *phb, struct pci_device *pd,\n \t\t\t  rev_class & 0xff, rev_class >> 8, cname, slotstr);\n }\n \n-\n-static void pci_add_one_node(struct phb *phb, struct pci_device *pd,\n-\t\t\t     struct dt_node *parent_node,\n-\t\t\t     struct pci_lsi_state *lstate, uint8_t swizzle)\n+static void pci_add_one_device_node(struct phb *phb,\n+\t\t\t\t    struct pci_device *pd,\n+\t\t\t\t    struct dt_node *parent_node,\n+\t\t\t\t    struct pci_lsi_state *lstate,\n+\t\t\t\t    uint8_t swizzle)\n {\n-\tstruct pci_device *child;\n \tstruct dt_node *np;\n \tconst char *cname;\n #define MAX_NAME 256\n@@ -1440,14 +1463,14 @@ static void pci_add_one_node(struct phb *phb, struct pci_device *pd,\n \t * Instead add a ranges property that explicitly translates 1:1.\n \t */\n \tdt_add_property(np, \"ranges\", ranges_direct, sizeof(ranges_direct));\n-\n-\tlist_for_each(&pd->children, child, link)\n-\t\tpci_add_one_node(phb, child, np, lstate, swizzle);\n }\n \n-static void pci_add_nodes(struct phb *phb)\n+void pci_add_device_nodes(struct phb *phb,\n+\t\t\t  struct list_head *list,\n+\t\t\t  struct dt_node *parent_node,\n+\t\t\t  struct pci_lsi_state *lstate,\n+\t\t\t  uint8_t swizzle)\n {\n-\tstruct pci_lsi_state *lstate = &phb->lstate;\n \tstruct pci_device *pd;\n \n \t/* If the PHB has its own slot info, add them */\n@@ -1455,8 +1478,15 @@ static void pci_add_nodes(struct phb *phb)\n \t\tpci_add_slot_properties(phb, phb->slot_info, NULL);\n \n \t/* Add all child devices */\n-\tlist_for_each(&phb->devices, pd, link)\n-\t\tpci_add_one_node(phb, pd, phb->dt_node, lstate, 0);\n+\tlist_for_each(list, pd, link) {\n+\t\tpci_add_one_device_node(phb, pd, parent_node,\n+\t\t\t\t\tlstate, swizzle);\n+\t\tif (list_empty(&pd->children))\n+\t\t\tcontinue;\n+\n+\t\tpci_add_device_nodes(phb, &pd->children,\n+\t\t\t\t     pd->dn, lstate, swizzle);\n+\t}\n }\n \n static void __pci_reset(struct list_head *list)\n@@ -1537,7 +1567,8 @@ void pci_init_slots(void)\n \tfor (i = 0; i < ARRAY_SIZE(phbs); i++) {\n \t\tif (!phbs[i])\n \t\t\tcontinue;\n-\t\tpci_add_nodes(phbs[i]);\n+\t\tpci_add_device_nodes(phbs[i], &phbs[i]->devices,\n+\t\t\t\t     phbs[i]->dt_node, &phbs[i]->lstate, 0);\n \t}\n \n \t/* PHB final fixup */\ndiff --git a/core/pcie-slot.c b/core/pcie-slot.c\nnew file mode 100644\nindex 0000000..62933a4\n--- /dev/null\n+++ b/core/pcie-slot.c\n@@ -0,0 +1,452 @@\n+/* Copyright 2013-2016 IBM Corp.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n+ * implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include <skiboot.h>\n+#include <opal-msg.h>\n+#include <pci-cfg.h>\n+#include <pci.h>\n+#include <pci-slot.h>\n+\n+/* Debugging options */\n+#define PCIE_SLOT_PREFIX\t\"PCIE-SLOT-%016llx \"\n+#define PCIE_SLOT_DBG(s, fmt, a...)\t\t  \\\n+\tprlog(PR_DEBUG, PCIE_SLOT_PREFIX fmt, (s)->id, ##a)\n+\n+static int64_t pcie_slot_get_presence_state(struct pci_slot *slot, uint8_t *val)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap;\n+\tuint16_t state;\n+\n+\t/* The presence is always on if it's a switch upstream port */\n+\tif (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT) {\n+\t\t*val = OPAL_PCI_SLOT_PRESENT;\n+\t\treturn OPAL_SUCCESS;\n+\t}\n+\n+\t/*\n+\t * The presence is always on if a switch downstream port\n+\t * doesn't support slot capability according to PCIE spec.\n+\t */\n+\tif (pd->dev_type == PCIE_TYPE_SWITCH_DNPORT &&\n+\t    !(slot->slot_cap & PCICAP_EXP_CAP_SLOT)) {\n+\t\t*val = OPAL_PCI_SLOT_PRESENT;\n+\t\treturn OPAL_SUCCESS;\n+\t}\n+\n+\t/* Retrieve presence status */\n+\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTSTAT, &state);\n+\tif (state & PCICAP_EXP_SLOTSTAT_PDETECTST)\n+\t\t*val = OPAL_PCI_SLOT_PRESENT;\n+\telse\n+\t\t*val = OPAL_PCI_SLOT_EMPTY;\n+\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t pcie_slot_get_link_state(struct pci_slot *slot,\n+\t\t\t\t\tuint8_t *val)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap;\n+\tint16_t state;\n+\n+\t/*\n+\t * The link behind switch upstream port is always on\n+\t * since it doesn't have a valid link indicator.\n+\t */\n+\tif (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT) {\n+\t\t*val = 1;\n+\t\treturn OPAL_SUCCESS;\n+\t}\n+\n+\t/* Retrieve link width */\n+\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LSTAT, &state);\n+\tif (state & PCICAP_EXP_LSTAT_DLLL_ACT)\n+\t\t*val = ((state & PCICAP_EXP_LSTAT_WIDTH) >> 4);\n+\telse\n+\t\t*val = 0;\n+\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t pcie_slot_get_power_state(struct pci_slot *slot __unused,\n+\t\t\t\t\t uint8_t *val)\n+{\n+\t/* The power is always on if no functionality is supported */\n+\tif (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL))\n+\t\t*val = PCI_SLOT_POWER_ON;\n+\telse\n+\t\t*val = slot->power_state;\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t pcie_slot_get_attention_state(struct pci_slot *slot,\n+\t\t\t\t\t     uint8_t *val)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap;\n+\tuint16_t state;\n+\n+\t/* Attention is off if the capability is missing */\n+\tif (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI)) {\n+\t\t*val = 0;\n+\t\treturn OPAL_SUCCESS;\n+\t}\n+\n+\t/* Retrieve attention state */\n+\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);\n+\tstate = (state & PCICAP_EXP_SLOTCTL_ATTNI) >> 6;\n+\tswitch (state) {\n+\tcase PCIE_INDIC_ON:\n+\t\t*val = PCI_SLOT_ATTN_LED_ON;\n+\t\tbreak;\n+\tcase PCIE_INDIC_BLINK:\n+\t\t*val = PCI_SLOT_ATTN_LED_BLINK;\n+\t\tbreak;\n+\tcase PCIE_INDIC_OFF:\n+\tdefault:\n+\t\t*val = PCI_SLOT_ATTN_LED_OFF;\n+\t}\n+\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t pcie_slot_get_latch_state(struct pci_slot *slot,\n+\t\t\t\t\t uint8_t *val)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap;\n+\tuint16_t state;\n+\n+\t/* Latch is off if MRL sensor doesn't exist */\n+\tif (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_MRLSENS)) {\n+\t\t*val = 0;\n+\t\treturn OPAL_SUCCESS;\n+\t}\n+\n+\t/* Retrieve MRL sensor state */\n+\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTSTAT, &state);\n+\tif (state & PCICAP_EXP_SLOTSTAT_MRLSENSST)\n+\t\t*val = 1;\n+\telse\n+\t\t*val = 0;\n+\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t pcie_slot_set_attention_state(struct pci_slot *slot,\n+\t\t\t\t\t     uint8_t val)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap;\n+\tuint16_t state;\n+\n+\t/* Drop the request if functionality doesn't exist */\n+\tif (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI))\n+\t\treturn OPAL_SUCCESS;\n+\n+\t/* Update with the requested state */\n+\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);\n+\tstate &= ~PCICAP_EXP_SLOTCTL_ATTNI;\n+\tswitch (val) {\n+\tcase PCI_SLOT_ATTN_LED_ON:\n+\t\tstate |= (PCIE_INDIC_ON << 6);\n+\t\tbreak;\n+\tcase PCI_SLOT_ATTN_LED_BLINK:\n+\t\tstate |= (PCIE_INDIC_BLINK << 6);\n+\t\tbreak;\n+\tcase PCI_SLOT_ATTN_LED_OFF:\n+\t\tstate |= (PCIE_INDIC_OFF << 6);\n+\t\tbreak;\n+\tdefault:\n+\t\tprlog(PR_ERR, PCIE_SLOT_PREFIX\n+\t\t      \"Invalid attention state (0x%x)\\n\", slot->id, val);\n+\t\treturn OPAL_PARAMETER;\n+\t}\n+\n+\tpci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, state);\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t pcie_slot_set_power_state(struct pci_slot *slot, uint8_t val)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap;\n+\tuint16_t state;\n+\n+\t/* Drop the request if functionality doesn't exist */\n+\tif (!(slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL))\n+\t\treturn OPAL_SUCCESS;\n+\n+\tif (slot->power_state == val)\n+\t\treturn OPAL_SUCCESS;\n+\n+\tpci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_START);\n+\tslot->power_state = val;\n+\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, &state);\n+\tstate &= ~(PCICAP_EXP_SLOTCTL_PWRCTLR | PCICAP_EXP_SLOTCTL_PWRI);\n+\tswitch (val) {\n+\tcase PCI_SLOT_POWER_OFF:\n+\t\tstate |= (PCICAP_EXP_SLOTCTL_PWRCTLR | (PCIE_INDIC_OFF << 8));\n+\t\tbreak;\n+\tcase PCI_SLOT_POWER_ON:\n+\t\tstate |= (PCIE_INDIC_ON << 8);\n+\t\tbreak;\n+\tdefault:\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\t\tprlog(PR_ERR, PCIE_SLOT_PREFIX\n+\t\t      \"Invalid power state (0x%x)\\n\", slot->id, val);\n+\t\treturn OPAL_PARAMETER;\n+\t}\n+\n+\tpci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCTL, state);\n+\tpci_slot_set_state(slot, PCI_SLOT_STATE_SPOWER_DONE);\n+\n+\treturn OPAL_ASYNC_COMPLETION;\n+}\n+\n+static int64_t pcie_slot_sm_poll_link(struct pci_slot *slot)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint32_t ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\tuint16_t val;\n+\tuint8_t presence = 0;\n+\n+\tswitch (slot->state) {\n+\tcase PCI_SLOT_STATE_LINK_START_POLL:\n+\t\tPCIE_SLOT_DBG(slot, \"LINK: Start polling\\n\");\n+\n+\t\t/* Link is down for ever without devices attached */\n+\t\tif (slot->ops.get_presence_state)\n+\t\t\tslot->ops.get_presence_state(slot, &presence);\n+\t\tif (!presence) {\n+\t\t\tPCIE_SLOT_DBG(slot, \"LINK: No adapter, end polling\\n\");\n+\t\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\t\t\treturn OPAL_SUCCESS;\n+\t\t}\n+\n+\t\t/* Enable the link without check */\n+\t\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LCTL, &val);\n+\t\tval &= ~PCICAP_EXP_LCTL_LINK_DIS;\n+\t\tpci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_LCTL, val);\n+\n+\t\t/*\n+\t\t * If the link change report isn't supported, we expect\n+\t\t * the link is up and stabilized after one second.\n+\t\t */\n+\t\tif (!(slot->link_cap & PCICAP_EXP_LCAP_DL_ACT_REP)) {\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\t\t   PCI_SLOT_STATE_LINK_DELAY_FINALIZED);\n+\t\t\treturn pci_slot_set_sm_timeout(slot, secs_to_tb(1));\n+\t\t}\n+\n+\t\t/*\n+\t\t * Poll the link state if link state change report is\n+\t\t * supported on the link.\n+\t\t */\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_LINK_POLLING);\n+\t\tslot->retries = 250;\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(20));\n+\tcase PCI_SLOT_STATE_LINK_DELAY_FINALIZED:\n+\t\tPCIE_SLOT_DBG(slot, \"LINK: No link report, end polling\\n\");\n+\t\tif (slot->ops.prepare_link_change)\n+\t\t\tslot->ops.prepare_link_change(slot, true);\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\t\treturn OPAL_SUCCESS;\n+\tcase PCI_SLOT_STATE_LINK_POLLING:\n+\t\tpci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_LSTAT, &val);\n+\t\tif (val & PCICAP_EXP_LSTAT_DLLL_ACT) {\n+\t\t\tPCIE_SLOT_DBG(slot, \"LINK: Link is up, end polling\\n\");\n+\t\t\tif (slot->ops.prepare_link_change)\n+\t\t\t\tslot->ops.prepare_link_change(slot, true);\n+\t\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\t\t\treturn OPAL_SUCCESS;\n+\t\t}\n+\n+\t\t/* Check link state again until timeout */\n+\t\tif (slot->retries-- == 0) {\n+\t\t\tprlog(PR_ERR, PCIE_SLOT_PREFIX\n+\t\t\t      \"LINK: Timeout waiting for up (%04x)\\n\",\n+\t\t\t      slot->id, val);\n+\t\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\t\t\treturn OPAL_SUCCESS;\n+\t\t}\n+\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(20));\n+\tdefault:\n+\t\tprlog(PR_ERR, PCIE_SLOT_PREFIX\n+\t\t      \"Link: Unexpected slot state %08x\\n\",\n+\t\t      slot->id, slot->state);\n+\t}\n+\n+\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\treturn OPAL_HARDWARE;\n+}\n+\n+static void pcie_slot_reset(struct pci_slot *slot, bool assert)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tuint16_t ctl;\n+\n+\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_BRCTL, &ctl);\n+\tif (assert)\n+\t\tctl |= PCI_CFG_BRCTL_SECONDARY_RESET;\n+\telse\n+\t\tctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;\n+\tpci_cfg_write16(phb, pd->bdfn, PCI_CFG_BRCTL, ctl);\n+}\n+\n+static int64_t pcie_slot_sm_hreset(struct pci_slot *slot)\n+{\n+\tswitch (slot->state) {\n+\tcase PCI_SLOT_STATE_NORMAL:\n+\t\tPCIE_SLOT_DBG(slot, \"HRESET: Starts\\n\");\n+\t\tif (slot->ops.prepare_link_change) {\n+\t\t\tPCIE_SLOT_DBG(slot, \"HRESET: Prepare for link down\\n\");\n+\t\t\tslot->ops.prepare_link_change(slot, false);\n+\t\t}\n+\t\t/* fall through */\n+\tcase PCI_SLOT_STATE_HRESET_START:\n+\t\tPCIE_SLOT_DBG(slot, \"HRESET: Assert\\n\");\n+\t\tpcie_slot_reset(slot, true);\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_HRESET_HOLD);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(250));\n+\tcase PCI_SLOT_STATE_HRESET_HOLD:\n+\t\tPCIE_SLOT_DBG(slot, \"HRESET: Deassert\\n\");\n+\t\tpcie_slot_reset(slot, false);\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_LINK_START_POLL);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(1800));\n+\tdefault:\n+\t\tPCIE_SLOT_DBG(slot, \"HRESET: Unexpected slot state %08x\\n\",\n+\t\t\t      slot->state);\n+\t}\n+\n+\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\treturn OPAL_HARDWARE;\n+}\n+\n+/*\n+ * Usually, individual platforms need to override the power\n+ * management methods for fundamental reset, but the hot\n+ * reset method is commonly shared.\n+ */\n+static int64_t pcie_slot_sm_freset(struct pci_slot *slot)\n+{\n+\tuint8_t power_state = PCI_SLOT_POWER_ON;\n+\n+\tswitch (slot->state) {\n+\tcase PCI_SLOT_STATE_NORMAL:\n+\t\tPCIE_SLOT_DBG(slot, \"FRESET: Starts\\n\");\n+\t\tif (slot->ops.prepare_link_change)\n+\t\t\tslot->ops.prepare_link_change(slot, false);\n+\n+\t\t/* Retrieve power state */\n+\t\tif (slot->ops.get_power_state) {\n+\t\t\tPCIE_SLOT_DBG(slot, \"FRESET: Retrieve power state\\n\");\n+\t\t\tslot->ops.get_power_state(slot, &power_state);\n+\t\t}\n+\n+\t\t/* In power on state, power it off */\n+\t\tif (power_state == PCI_SLOT_POWER_ON &&\n+\t\t    slot->ops.set_power_state) {\n+\t\t\tPCIE_SLOT_DBG(slot, \"FRESET: Power is on, turn off\\n\");\n+\t\t\tslot->ops.set_power_state(slot, PCI_SLOT_POWER_OFF);\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tPCI_SLOT_STATE_FRESET_POWER_OFF);\n+\t\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(50));\n+\t\t}\n+\t\t/* No power state change, fall through */\n+\tcase PCI_SLOT_STATE_FRESET_POWER_OFF:\n+\t\tPCIE_SLOT_DBG(slot, \"FRESET: Power is off, turn on\\n\");\n+\t\tif (slot->ops.set_power_state)\n+\t\t\tslot->ops.set_power_state(slot, PCI_SLOT_POWER_ON);\n+\t\tpci_slot_set_state(slot, PCI_SLOT_STATE_HRESET_START);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(50));\n+\tdefault:\n+\t\tprlog(PR_ERR, PCIE_SLOT_PREFIX\n+\t\t      \"FRESET: Unexpected slot state %08x\\n\",\n+\t\t      slot->id, slot->state);\n+\t}\n+\n+\tpci_slot_set_state(slot, PCI_SLOT_STATE_NORMAL);\n+\treturn OPAL_HARDWARE;\n+}\n+\n+struct pci_slot *pcie_slot_create(struct phb *phb, struct pci_device *pd)\n+{\n+\tstruct pci_slot *slot;\n+\tuint32_t ecap;\n+\n+\t/* Allocate PCI slot */\n+\tslot = pci_slot_alloc(phb, pd);\n+\tif (!slot)\n+\t\treturn NULL;\n+\n+\t/* Cache the link and slot capabilities */\n+\tif (pd) {\n+\t\tecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);\n+\t\tpci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_LCAP,\n+\t\t\t       &slot->link_cap);\n+\t\tpci_cfg_read32(phb, pd->bdfn, ecap + PCICAP_EXP_SLOTCAP,\n+\t\t\t       &slot->slot_cap);\n+\t}\n+\n+\tif ((slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_SURP) &&\n+\t    (slot->slot_cap & PCICAP_EXP_SLOTCAP_HPLUG_CAP))\n+\t\tslot->pluggable = 1;\n+\tif (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWCTRL)\n+\t\tslot->power_ctl = 1;\n+\tif (slot->slot_cap & PCICAP_EXP_SLOTCAP_PWRI)\n+\t\tslot->power_led_ctl = PCI_SLOT_PWR_LED_CTL_KERNEL;\n+\tif (slot->slot_cap & PCICAP_EXP_SLOTCAP_ATTNI)\n+\t\tslot->attn_led_ctl = PCI_SLOT_ATTN_LED_CTL_KERNEL;\n+\tslot->wired_lanes = ((slot->link_cap & PCICAP_EXP_LCAP_MAXWDTH) >> 4);\n+\n+\t/* Standard slot operations */\n+\tslot->ops.get_presence_state  = pcie_slot_get_presence_state;\n+\tslot->ops.get_link_state      = pcie_slot_get_link_state;\n+\tslot->ops.get_power_state     = pcie_slot_get_power_state;\n+\tslot->ops.get_attention_state = pcie_slot_get_attention_state;\n+\tslot->ops.get_latch_state     = pcie_slot_get_latch_state;\n+\tslot->ops.set_power_state     = pcie_slot_set_power_state;\n+\tslot->ops.set_attention_state = pcie_slot_set_attention_state;\n+\n+\t/*\n+\t * State machine (SM) based reset stuff. The poll function is always\n+\t * unified for all cases.\n+\t */\n+\tslot->ops.poll_link             = pcie_slot_sm_poll_link;\n+\tslot->ops.hreset                = pcie_slot_sm_hreset;\n+\tslot->ops.freset                = pcie_slot_sm_freset;\n+\tslot->ops.pfreset               = NULL;\n+\n+\treturn slot;\n+}\ndiff --git a/include/opal-api.h b/include/opal-api.h\nindex 41af0e5..2b8bf57 100644\n--- a/include/opal-api.h\n+++ b/include/opal-api.h\n@@ -376,6 +376,16 @@ enum OpalPciMaskAction {\n \tOPAL_MASK_ERROR_TYPE = 1\n };\n \n+enum OpalPciSlotPresence {\n+\tOPAL_PCI_SLOT_EMPTY\t= 0,\n+\tOPAL_PCI_SLOT_PRESENT\t= 1\n+};\n+\n+enum OpalPciSlotPower {\n+\tOPAL_PCI_SLOT_POWER_OFF\t= 0,\n+\tOPAL_PCI_SLOT_POWER_ON\t= 1\n+};\n+\n enum OpalSlotLedType {\n \tOPAL_SLOT_LED_TYPE_ID = 0,\t/* IDENTIFY LED */\n \tOPAL_SLOT_LED_TYPE_FAULT = 1,\t/* FAULT LED */\ndiff --git a/include/pci-slot.h b/include/pci-slot.h\nnew file mode 100644\nindex 0000000..cf22432\n--- /dev/null\n+++ b/include/pci-slot.h\n@@ -0,0 +1,255 @@\n+/* Copyright 2013-2016 IBM Corp.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n+ * implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#ifndef __PCI_SLOT_H\n+#define __PCI_SLOT_H\n+\n+#include <opal.h>\n+#include <device.h>\n+#include <timebase.h>\n+#include <timer.h>\n+#include <ccan/list/list.h>\n+\n+/*\n+ * PCI Slot Info: Wired Lane Values\n+ *\n+ * Values 0 to 6 match slot map 1005. In case of *any* change here\n+ * make sure to keep the lxvpd.c parsing code in sync *and* the\n+ * corresponding label strings in pci.c\n+ */\n+#define PCI_SLOT_WIRED_LANES_UNKNOWN\t0x00\n+#define PCI_SLOT_WIRED_LANES_PCIE_X1\t0x01\n+#define PCI_SLOT_WIRED_LANES_PCIE_X2\t0x02\n+#define PCI_SLOT_WIRED_LANES_PCIE_X4\t0x03\n+#define PCI_SLOT_WIRED_LANES_PCIE_X8\t0x04\n+#define PCI_SLOT_WIRED_LANES_PCIE_X16\t0x05\n+#define PCI_SLOT_WIRED_LANES_PCIE_X32\t0x06\n+#define PCI_SLOT_WIRED_LANES_PCIX_32\t0x07\n+#define PCI_SLOT_WIRED_LANES_PCIX_64\t0x08\n+\n+/* PCI Slot Info: Bus Clock Values */\n+#define PCI_SLOT_BUS_CLK_RESERVED\t0x00\n+#define PCI_SLOT_BUS_CLK_GEN_1\t\t0x01\n+#define PCI_SLOT_BUS_CLK_GEN_2\t\t0x02\n+#define PCI_SLOT_BUS_CLK_GEN_3\t\t0x03\n+\n+/* PCI Slot Info: Connector Type Values */\n+#define PCI_SLOT_CONNECTOR_PCIE_EMBED\t0x00\n+#define PCI_SLOT_CONNECTOR_PCIE_X1\t0x01\n+#define PCI_SLOT_CONNECTOR_PCIE_X2\t0x02\n+#define PCI_SLOT_CONNECTOR_PCIE_X4\t0x03\n+#define PCI_SLOT_CONNECTOR_PCIE_X8\t0x04\n+#define PCI_SLOT_CONNECTOR_PCIE_X16\t0x05\n+#define PCI_SLOT_CONNECTOR_PCIE_NS\t0x0E\t/* Non-Standard */\n+\n+/* PCI Slot Info: Card Description Values */\n+#define PCI_SLOT_DESC_NON_STANDARD\t0x00\t/* Embed/Non-Standard       */\n+#define PCI_SLOT_DESC_PCIE_FH_FL\t0x00\t/* Full Height, Full Length */\n+#define PCI_SLOT_DESC_PCIE_FH_HL\t0x01\t/* Full Height, Half Length */\n+#define PCI_SLOT_DESC_PCIE_HH_FL\t0x02\t/* Half Height, Full Length */\n+#define PCI_SLOT_DESC_PCIE_HH_HL\t0x03\t/* Half Height, Half Length */\n+\n+/* PCI Slot Info: Mechanicals Values */\n+#define PCI_SLOT_MECH_NONE\t\t0x00\n+#define PCI_SLOT_MECH_RIGHT\t\t0x01\n+#define PCI_SLOT_MECH_LEFT\t\t0x02\n+#define PCI_SLOT_MECH_RIGHT_LEFT\t0x03\n+\n+/* PCI Slot Info: Power LED Control Values */\n+#define PCI_SLOT_PWR_LED_CTL_NONE\t0x00\t/* No Control        */\n+#define PCI_SLOT_PWR_LED_CTL_FSP\t0x01\t/* FSP Controlled    */\n+#define PCI_SLOT_PWR_LED_CTL_KERNEL\t0x02\t/* Kernel Controlled */\n+\n+/* PCI Slot Info: ATTN LED Control Values */\n+#define PCI_SLOT_ATTN_LED_CTL_NONE\t0x00\t/* No Control        */\n+#define PCI_SLOT_ATTN_LED_CTL_FSP\t0x01\t/* FSP Controlled    */\n+#define PCI_SLOT_ATTN_LED_CTL_KERNEL\t0x02\t/* Kernel Controlled */\n+\n+/* Attention LED */\n+#define PCI_SLOT_ATTN_LED_OFF\t\t0\n+#define PCI_SLOT_ATTN_LED_ON\t\t1\n+#define PCI_SLOT_ATTN_LED_BLINK\t\t2\n+\n+/* Power state */\n+#define PCI_SLOT_POWER_OFF\t\t0\n+#define PCI_SLOT_POWER_ON\t\t1\n+\n+/*\n+ * We have hard and soft reset for slot. Hard reset requires\n+ * power-off and then power-on, but soft reset only resets\n+ * secondary bus.\n+ */\n+struct pci_slot;\n+struct pci_slot_ops {\n+\t/* For slot management */\n+\tint64_t (*get_presence_state)(struct pci_slot *slot, uint8_t *val);\n+\tint64_t (*get_link_state)(struct pci_slot *slot, uint8_t *val);\n+\tint64_t (*get_power_state)(struct pci_slot *slot, uint8_t *val);\n+\tint64_t (*get_attention_state)(struct pci_slot *slot, uint8_t *val);\n+\tint64_t (*get_latch_state)(struct pci_slot *slot, uint8_t *val);\n+\tint64_t (*set_power_state)(struct pci_slot *slot, uint8_t val);\n+\tint64_t (*set_attention_state)(struct pci_slot *slot, uint8_t val);\n+\n+\t/* SM based functions for reset */\n+\tvoid (*prepare_link_change)(struct pci_slot *slot, bool is_up);\n+\tint64_t (*poll_link)(struct pci_slot *slot);\n+\tint64_t (*creset)(struct pci_slot *slot);\n+\tint64_t (*freset)(struct pci_slot *slot);\n+\tint64_t (*pfreset)(struct pci_slot *slot);\n+\tint64_t (*hreset)(struct pci_slot *slot);\n+\tint64_t (*poll)(struct pci_slot *slot);\n+\n+\t/* Auxillary functions */\n+\tvoid (*add_properties)(struct pci_slot *slot, struct dt_node *np);\n+};\n+\n+/*\n+ * The PCI slot state is split up into base and number. With this\n+ * design, the individual platforms can introduce their own PCI\n+ * slot states with addition to the base. Eventually, the base\n+ * state can be recognized by PCI slot core.\n+ */\n+#define PCI_SLOT_STATE_MASK\t\t\t0xFFFFFF00\n+#define PCI_SLOT_STATE_NORMAL\t\t\t0x00000000\n+#define PCI_SLOT_STATE_LINK\t\t\t0x00000100\n+#define   PCI_SLOT_STATE_LINK_START_POLL\t0x00000101\n+#define   PCI_SLOT_STATE_LINK_DELAY_FINALIZED\t0x00000102\n+#define   PCI_SLOT_STATE_LINK_POLLING\t\t0x00000103\n+#define PCI_SLOT_STATE_HRESET\t\t\t0x00000200\n+#define   PCI_SLOT_STATE_HRESET_START\t\t0x00000201\n+#define   PCI_SLOT_STATE_HRESET_HOLD\t\t0x00000202\n+#define PCI_SLOT_STATE_FRESET\t\t\t0x00000300\n+#define   PCI_SLOT_STATE_FRESET_POWER_OFF\t0x00000301\n+#define PCI_SLOT_STATE_PFRESET\t\t\t0x00000400\n+#define   PCI_SLOT_STATE_PFRESET_START\t\t0x00000401\n+#define PCI_SLOT_STATE_CRESET\t\t\t0x00000500\n+#define   PCI_SLOT_STATE_CRESET_START\t\t0x00000501\n+#define PCI_SLOT_STATE_GPOWER\t\t\t0x00000600\n+#define   PCI_SLOT_STATE_GPOWER_START\t\t0x00000601\n+#define PCI_SLOT_STATE_SPOWER\t\t\t0x00000700\n+#define   PCI_SLOT_STATE_SPOWER_START\t\t0x00000701\n+#define   PCI_SLOT_STATE_SPOWER_DONE\t\t0x00000702\n+#define PCI_SLOT_STATE_GPRESENCE\t\t0x00000800\n+#define   PCI_SLOT_STATE_GPRESENCE_START\t0x00000801\n+\n+\n+struct pci_slot {\n+\tuint32_t\t\tflags;\n+#define PCI_SLOT_FLAG_BOOTUP\t\t0x1\n+\n+\tstruct phb\t\t*phb;\n+\tstruct pci_device\t*pd;\n+\n+\t/* Identifier */\n+\tuint64_t\t\tid;\n+\tstruct timer\t\ttimer;\n+\tuint64_t\t\tasync_token;\n+\tuint8_t\t\t\tpower_state;\n+\n+\t/* Slot information */\n+\tuint8_t\t\t\tpluggable;\n+\tuint8_t\t\t\tpower_ctl;\n+\tuint8_t\t\t\tpower_led_ctl;\n+\tuint8_t\t\t\tattn_led_ctl;\n+\tuint8_t\t\t\tconnector_type;\n+\tuint8_t\t\t\tcard_desc;\n+\tuint8_t\t\t\tcard_mech;\n+\tuint8_t\t\t\twired_lanes;\n+\n+\t/*\n+\t * PCI slot is driven by state machine with polling function.\n+\t * @delay_tgt_tb tracks the current delay while @retries has\n+\t * the left rounds of delays. They should be set prior to\n+\t * switching next PCI slot state and changed (decreased)\n+\t * accordingly in the polling function.\n+\t */\n+\tuint32_t\t\tstate;\n+\tuint32_t\t\tretry_state;\n+\tuint32_t\t\tlink_cap;\n+\tuint32_t\t\tslot_cap;\n+\tuint64_t\t\tdelay_tgt_tb;\n+\tuint64_t\t\tretries;\n+\tstruct pci_slot_ops\tops;\n+\tvoid\t\t\t*data;\n+};\n+\n+#define PCI_SLOT_ID_PREFIX\t0x8000000000000000\n+#define PCI_SLOT_ID(phb, bdfn)\t\\\n+\t(PCI_SLOT_ID_PREFIX | ((uint64_t)(bdfn) << 16) | (phb)->opal_id)\n+#define PCI_PHB_SLOT_ID(phb)\t((phb)->opal_id)\n+#define PCI_SLOT_PHB_INDEX(id)\t((id) & 0xfffful)\n+#define PCI_SLOT_BDFN(id)\t(((id) >> 16) & 0xfffful)\n+\n+static inline uint32_t pci_slot_add_flags(struct pci_slot *slot,\n+\t\t\t\t\t  uint32_t flags)\n+{\n+\tuint32_t old = 0;\n+\n+\tif (slot) {\n+\t\told = slot->flags;\n+\t\tslot->flags |= flags;\n+\t}\n+\n+\treturn old;\n+}\n+\n+static inline bool pci_slot_has_flags(struct pci_slot *slot,\n+\t\t\t\t      uint32_t flags)\n+{\n+\tif (!slot)\n+\t\treturn false;\n+\n+\tif ((slot->flags & flags) == flags)\n+\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+static inline uint32_t pci_slot_remove_flags(struct pci_slot *slot,\n+\t\t\t\t\t     uint32_t flags)\n+{\n+\tuint32_t old = 0;\n+\n+\tif (slot) {\n+\t\told = slot->flags;\n+\t\tslot->flags &= ~flags;\n+\t}\n+\n+\treturn old;\n+}\n+\n+static inline void pci_slot_set_state(struct pci_slot *slot, uint32_t state)\n+{\n+\tif (slot)\n+\t\tslot->state = state;\n+}\n+\n+static inline uint64_t pci_slot_set_sm_timeout(struct pci_slot *slot,\n+\t\t\t\t\t       uint64_t dur)\n+{\n+\tif (slot)\n+\t\tslot->delay_tgt_tb = mftb() + dur;\n+\treturn dur;\n+}\n+\n+extern struct pci_slot *pci_slot_alloc(struct phb *phb,\n+\t\t\t\t       struct pci_device *pd);\n+extern struct pci_slot *pcie_slot_create(struct phb *phb,\n+\t\t\t\t\t struct pci_device *pd);\n+extern void pci_slot_add_dt_properties(struct pci_slot *slot,\n+\t\t\t\t       struct dt_node *np);\n+extern struct pci_slot *pci_slot_find(uint64_t id);\n+#endif /* __PCI_SLOT_H */\ndiff --git a/include/pci.h b/include/pci.h\nindex 69be49e..486b712 100644\n--- a/include/pci.h\n+++ b/include/pci.h\n@@ -22,60 +22,6 @@\n #include <lock.h>\n #include <ccan/list/list.h>\n \n-/* PCI Slot Info: Wired Lane Values\n- *\n- * Values 0 to 6 match slot map 1005. In case of *any* change here\n- * make sure to keep the lxvpd.c parsing code in sync *and* the\n- * corresponding label strings in pci.c\n- */\n-#define PCI_SLOT_WIRED_LANES_UNKNOWN   0x00\n-#define PCI_SLOT_WIRED_LANES_PCIE_X1   0x01\n-#define PCI_SLOT_WIRED_LANES_PCIE_X2   0x02\n-#define PCI_SLOT_WIRED_LANES_PCIE_X4   0x03\n-#define PCI_SLOT_WIRED_LANES_PCIE_X8   0x04\n-#define PCI_SLOT_WIRED_LANES_PCIE_X16  0x05\n-#define PCI_SLOT_WIRED_LANES_PCIE_X32  0x06\n-#define PCI_SLOT_WIRED_LANES_PCIX_32   0x07\n-#define PCI_SLOT_WIRED_LANES_PCIX_64   0x08\n-\n-/* PCI Slot Info: Bus Clock Values */\n-#define PCI_SLOT_BUS_CLK_RESERVED      0x00\n-#define PCI_SLOT_BUS_CLK_GEN_1         0x01\n-#define PCI_SLOT_BUS_CLK_GEN_2         0x02\n-#define PCI_SLOT_BUS_CLK_GEN_3         0x03\n-\n-/* PCI Slot Info: Connector Type Values */\n-#define PCI_SLOT_CONNECTOR_PCIE_EMBED  0x00\n-#define PCI_SLOT_CONNECTOR_PCIE_X1     0x01\n-#define PCI_SLOT_CONNECTOR_PCIE_X2     0x02\n-#define PCI_SLOT_CONNECTOR_PCIE_X4     0x03\n-#define PCI_SLOT_CONNECTOR_PCIE_X8     0x04\n-#define PCI_SLOT_CONNECTOR_PCIE_X16    0x05\n-#define PCI_SLOT_CONNECTOR_PCIE_NS     0x0E  /* Non-Standard */\n-\n-/* PCI Slot Info: Card Description Values */\n-#define PCI_SLOT_DESC_NON_STANDARD     0x00 /* Embed/Non-Standard Connector */\n-#define PCI_SLOT_DESC_PCIE_FH_FL       0x00 /* Full Height, Full Length */\n-#define PCI_SLOT_DESC_PCIE_FH_HL       0x01 /* Full Height, Half Length */\n-#define PCI_SLOT_DESC_PCIE_HH_FL       0x02 /* Half Height, Full Length */\n-#define PCI_SLOT_DESC_PCIE_HH_HL       0x03 /* Half Height, Half Length */\n-\n-/* PCI Slot Info: Mechanicals Values */\n-#define PCI_SLOT_MECH_NONE             0x00\n-#define PCI_SLOT_MECH_RIGHT            0x01\n-#define PCI_SLOT_MECH_LEFT             0x02\n-#define PCI_SLOT_MECH_RIGHT_LEFT       0x03\n-\n-/* PCI Slot Info: Power LED Control Values */\n-#define PCI_SLOT_PWR_LED_CTL_NONE      0x00 /* No Control        */\n-#define PCI_SLOT_PWR_LED_CTL_FSP       0x01 /* FSP Controlled    */\n-#define PCI_SLOT_PWR_LED_CTL_KERNEL    0x02 /* Kernel Controlled */\n-\n-/* PCI Slot Info: ATTN LED Control Values */\n-#define PCI_SLOT_ATTN_LED_CTL_NONE     0x00 /* No Control        */\n-#define PCI_SLOT_ATTN_LED_CTL_FSP      0x01 /* FSP Controlled    */\n-#define PCI_SLOT_ATTN_LED_CTL_KERNEL   0x02 /* Kernel Controlled */\n-\n /* PCI Slot Entry Information */\n struct pci_slot_info {\n \tchar       label[16];\n@@ -151,6 +97,7 @@ struct pci_device {\n \tstruct list_head\tpcrf;\n \n \tstruct dt_node\t\t*dn;\n+\tstruct pci_slot\t\t*slot;\n \tstruct pci_slot_info    *slot_info;\n \tstruct pci_device\t*parent;\n \tstruct list_head\tchildren;\n@@ -462,6 +409,7 @@ struct phb {\n \tuint32_t\t\tmps;\n \n \t/* PCI-X only slot info, for PCI-E this is in the RC bridge */\n+\tstruct pci_slot\t\t*slot;\n \tstruct pci_slot_info    *slot_info;\n \n \t/* Base location code used to generate the children one */\n@@ -519,7 +467,15 @@ static inline int64_t pci_cfg_write32(struct phb *phb, uint32_t bdfn,\n }\n \n /* Utilities */\n-\n+extern void pci_remove_bus(struct phb *phb, struct list_head *list);\n+extern uint8_t pci_scan_bus(struct phb *phb, uint8_t bus, uint8_t max_bus,\n+\t\t\t    struct list_head *list, struct pci_device *parent,\n+\t\t\t    bool scan_downstream);\n+extern void pci_add_device_nodes(struct phb *phb,\n+\t\t\t\t struct list_head *list,\n+\t\t\t\t struct dt_node *parent_node,\n+\t\t\t\t struct pci_lsi_state *lstate,\n+\t\t\t\t uint8_t swizzle);\n extern int64_t pci_find_cap(struct phb *phb, uint16_t bdfn, uint8_t cap);\n extern int64_t pci_find_ecap(struct phb *phb, uint16_t bdfn, uint16_t cap,\n \t\t\t     uint8_t *version);\ndiff --git a/include/platform.h b/include/platform.h\nindex f1bdc30..d07994f 100644\n--- a/include/platform.h\n+++ b/include/platform.h\n@@ -20,6 +20,7 @@\n /* Some fwd declarations for types used further down */\n struct phb;\n struct pci_device;\n+struct pci_slot;\n struct errorlog;\n \n enum resource_id {\ndiff --git a/platforms/ibm-fsp/lxvpd.c b/platforms/ibm-fsp/lxvpd.c\nindex 90c9e09..542c49a 100644\n--- a/platforms/ibm-fsp/lxvpd.c\n+++ b/platforms/ibm-fsp/lxvpd.c\n@@ -24,6 +24,7 @@\n #include <vpd.h>\n #include <pci.h>\n #include <pci-cfg.h>\n+#include <pci-slot.h>\n \n #include \"lxvpd.h\"\n \n",
    "prefixes": [
        "v12",
        "13/23"
    ]
}