Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/633516/?format=api
{ "id": 633516, "url": "http://patchwork.ozlabs.org/api/patches/633516/?format=api", "web_url": "http://patchwork.ozlabs.org/project/skiboot/patch/1465535032-26749-17-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-17-git-send-email-gwshan@linux.vnet.ibm.com>", "list_archive_url": null, "date": "2016-06-10T05:03:45", "name": "[v12,16/23] hw/phb3: Support PHB slot", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "b8e1112905f1f2b9cec0ec197f93274a9e620553", "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-17-git-send-email-gwshan@linux.vnet.ibm.com/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/633516/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/633516/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 [IPv6:2401:3900:2:1::3])\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 3rQqt21W5Pz9sD3\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Jun 2016 15:07:22 +1000 (AEST)", "from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3rQqt20Xq9zDqcb\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Jun 2016 15:07:22 +1000 (AEST)", "from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com\n\t[148.163.156.1])\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 3rQqr93pW0zDqNq\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:45 +1000 (AEST)", "from pps.filterd (m0098396.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id\n\tu5A53o3u048862\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 mx0a-001b2d01.pphosted.com with ESMTP id 23fm6djyrn-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:43 -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:38 +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:28 +1000", "from d23relay09.au.ibm.com (d23relay09.au.ibm.com [9.185.63.181])\n\tby d23dlp02.au.ibm.com (Postfix) with ESMTP id EC0312BB006A\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:20 +1000 (EST)", "from d23av02.au.ibm.com (d23av02.au.ibm.com [9.190.235.138])\n\tby d23relay09.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id\n\tu5A555N657540724\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:10 +1000", "from d23av02.au.ibm.com (localhost [127.0.0.1])\n\tby d23av02.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id\n\tu5A54xiq025420\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 d23av02.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id\n\tu5A54x6O025243; 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 C1F1AA0210;\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 BFD43E3B1A;\n\tFri, 10 Jun 2016 15:03:58 +1000 (AEST)", "by gwshan (Postfix, from userid 1000)\n\tid A5CCD942CA3; Fri, 10 Jun 2016 15:03:58 +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:45 +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-0000016C917B", "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused", "x-cbparentid": "16061005-0005-0000-0000-0000080CBB6E", "Message-Id": "<1465535032-26749-17-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=1\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 16/23] hw/phb3: Support PHB 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": "The patch refactors functions used for PHB slot management for\nPHB3. Also, PHB slots are created before platform's PHB setup\nhook (platform.pci_setup_phb()). That means the platforms can\noverride the properties or methods of the PHB slot if necessary.\n\nSigned-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>\nReviewed-by: Russell Currey <ruscur@russell.cc>\n---\n hw/phb3.c | 677 +++++++++++++++++++++++----------------------------------\n include/phb3.h | 52 +++--\n 2 files changed, 306 insertions(+), 423 deletions(-)", "diff": "diff --git a/hw/phb3.c b/hw/phb3.c\nindex 0c69122..9890564 100644\n--- a/hw/phb3.c\n+++ b/hw/phb3.c\n@@ -16,8 +16,9 @@\n #include <skiboot.h>\n #include <io.h>\n #include <timebase.h>\n-#include <pci.h>\n #include <pci-cfg.h>\n+#include <pci.h>\n+#include <pci-slot.h>\n #include <vpd.h>\n #include <interrupts.h>\n #include <opal.h>\n@@ -56,19 +57,6 @@ static inline void phb3_ioda_sel(struct phb3 *p, uint32_t table,\n \t\t SETFIELD(PHB_IODA_AD_TADR, 0ul, addr));\n }\n \n-/* Helper to set the state machine timeout */\n-static inline uint64_t phb3_set_sm_timeout(struct phb3 *p, uint64_t dur)\n-{\n-\tuint64_t target, now = mftb();\n-\n-\ttarget = now + dur;\n-\tif (target == 0)\n-\t\ttarget++;\n-\tp->delay_tgt_tb = target;\n-\n-\treturn dur;\n-}\n-\n /* Check if AIB is fenced via PBCQ NFIR */\n static bool phb3_fenced(struct phb3 *p)\n {\n@@ -570,38 +558,6 @@ static int64_t phb3_pci_reinit(struct phb *phb, uint64_t scope, uint64_t data)\n \treturn OPAL_SUCCESS;\n }\n \n-static int64_t phb3_presence_detect(struct phb *phb)\n-{\n-\tstruct phb3 *p = phb_to_phb3(phb);\n-\tuint64_t hp_override;\n-\n-\t/* Test for PHB in error state ? */\n-\tif (p->state == PHB3_STATE_BROKEN)\n-\t\treturn OPAL_HARDWARE;\n-\n-\t/* XXX Check bifurcation stuff ? */\n-\n-\t/* Read hotplug override */\n-\thp_override = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);\n-\n-\tPHBDBG(p, \"hp_override: 0x%016llx\\n\", hp_override);\n-\n-\t/*\n-\t * On P8, the slot status isn't wired up properly, we have to\n-\t * use the hotplug override A/B bits.\n-\t */\n-\tif ((hp_override & PHB_HPOVR_PRESENCE_A) &&\n-\t (hp_override & PHB_HPOVR_PRESENCE_B))\n-\t\treturn OPAL_SHPC_DEV_NOT_PRESENT;\n-\n-\t/*\n-\t * Anything else, we assume device present, the link state\n-\t * machine will perform an early bail out if no electrical\n-\t * signaling is established after a second.\n-\t */\n-\treturn OPAL_SHPC_DEV_PRESENT;\n-}\n-\n /* Clear IODA cache tables */\n static void phb3_init_ioda_cache(struct phb3 *p)\n {\n@@ -1980,139 +1936,145 @@ static int64_t phb3_set_peltv(struct phb *phb,\n \treturn OPAL_SUCCESS;\n }\n \n-static int64_t phb3_link_state(struct phb *phb)\n+static void phb3_prepare_link_change(struct pci_slot *slot,\n+\t\t\t\t bool is_up)\n {\n-\tstruct phb3 *p = phb_to_phb3(phb);\n-\tuint64_t reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);\n-\tuint16_t lstat;\n-\tint64_t rc;\n-\n-\t/* XXX Test for PHB in error state ? */\n-\n-\t/* Link is up, let's find the actual speed */\n-\tif (!(reg & PHB_PCIE_DLP_TC_DL_LINKACT))\n-\t\treturn OPAL_SHPC_LINK_DOWN;\n-\n-\trc = phb3_pcicfg_read16(&p->phb, 0, p->ecap + PCICAP_EXP_LSTAT,\n-\t\t\t\t&lstat);\n-\tif (rc < 0) {\n-\t\t/* Shouldn't happen */\n-\t\tPHBERR(p, \"Failed to read link status\\n\");\n-\t\treturn OPAL_HARDWARE;\n-\t}\n-\tif (!(lstat & PCICAP_EXP_LSTAT_DLLL_ACT))\n-\t\treturn OPAL_SHPC_LINK_DOWN;\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n+\tuint32_t reg32;\n \n-\treturn GETFIELD(PCICAP_EXP_LSTAT_WIDTH, lstat);\n-}\n+\tp->has_link = is_up;\n+\tif (!is_up) {\n+\t\t/* Mask PCIE port interrupts */\n+\t\tout_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,\n+\t\t\t 0xad42800000000000);\n \n-static int64_t phb3_power_state(struct phb __unused *phb)\n-{\n-\t/* XXX Test for PHB in error state ? */\n+\t\t/* Mask AER receiver error */\n+\t\tphb3_pcicfg_read32(&p->phb, 0,\n+\t\t\t\t p->aercap + PCIECAP_AER_CE_MASK, ®32);\n+\t\treg32 |= PCIECAP_AER_CE_RECVR_ERR;\n+\t\tphb3_pcicfg_write32(&p->phb, 0,\n+\t\t\t\t p->aercap + PCIECAP_AER_CE_MASK, reg32);\n \n-\t/* XXX TODO - External power control ? */\n+\t\t/* Block PCI-CFG access */\n+\t\tp->flags |= PHB3_CFG_BLOCKED;\n+\t} else {\n+\t\t/* Clear AER receiver error status */\n+\t\tphb3_pcicfg_write32(&p->phb, 0,\n+\t\t\t\t p->aercap + PCIECAP_AER_CE_STATUS,\n+\t\t\t\t PCIECAP_AER_CE_RECVR_ERR);\n+\n+\t\t/* Unmask receiver error status in AER */\n+\t\tphb3_pcicfg_read32(&p->phb, 0,\n+\t\t\t\t p->aercap + PCIECAP_AER_CE_MASK, ®32);\n+\t\treg32 &= ~PCIECAP_AER_CE_RECVR_ERR;\n+\t\tphb3_pcicfg_write32(&p->phb, 0,\n+\t\t\t\t p->aercap + PCIECAP_AER_CE_MASK, reg32);\n+\n+\t\t/* Clear spurrious errors and enable PCIE port interrupts */\n+\t\tout_be64(p->regs + UTL_PCIE_PORT_STATUS,\n+\t\t\t 0xffdfffffffffffff);\n+\t\tout_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,\n+\t\t\t 0xad5a800000000000);\n+\n+\t\t/* Don't block PCI-CFG */\n+\t\tp->flags &= ~PHB3_CFG_BLOCKED;\n \n-\treturn OPAL_SHPC_POWER_ON;\n+\t\t/*\n+\t\t * We might lose the bus numbers during the reset operation\n+\t\t * and we need to restore them. Otherwise, some adapters (e.g.\n+\t\t * IPR) can't be probed properly by the kernel. We don't need\n+\t\t * to restore bus numbers for every kind of reset, however,\n+\t\t * it's not harmful to always restore the bus numbers, which\n+\t\t * simplifies the logic.\n+\t\t */\n+\t\tpci_restore_bridge_buses(slot->phb, slot->pd);\n+\t\tif (slot->phb->ops->device_init)\n+\t\t\tpci_walk_dev(slot->phb, slot->pd,\n+\t\t\t\t slot->phb->ops->device_init, NULL);\n+\t}\n }\n \n-static int64_t phb3_slot_power_off(struct phb *phb)\n+static int64_t phb3_get_presence_state(struct pci_slot *slot, uint8_t *val)\n {\n-\tstruct phb3 *p = phb_to_phb3(phb);\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n+\tuint64_t hp_override;\n \n \tif (p->state == PHB3_STATE_BROKEN)\n \t\treturn OPAL_HARDWARE;\n-\tif (p->state != PHB3_STATE_FUNCTIONAL)\n-\t\treturn OPAL_BUSY;\n \n-\t/* XXX TODO - External power control ? */\n+\t/*\n+\t * On P8, the slot status isn't wired up properly, we have\n+\t * to use the hotplug override A/B bits.\n+\t */\n+\thp_override = in_be64(p->regs + PHB_HOTPLUG_OVERRIDE);\n+\tif ((hp_override & PHB_HPOVR_PRESENCE_A) &&\n+\t (hp_override & PHB_HPOVR_PRESENCE_B))\n+\t\t*val = OPAL_PCI_SLOT_EMPTY;\n+\telse\n+\t\t*val = OPAL_PCI_SLOT_PRESENT;\n \n \treturn OPAL_SUCCESS;\n }\n \n-static int64_t phb3_slot_power_on(struct phb *phb)\n+static int64_t phb3_get_link_state(struct pci_slot *slot, uint8_t *val)\n {\n-\tstruct phb3 *p = phb_to_phb3(phb);\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n+\tuint64_t reg;\n+\tuint16_t state;\n+\tint64_t rc;\n \n-\tif (p->state == PHB3_STATE_BROKEN)\n+\t/* Link is up, let's find the actual speed */\n+\treg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);\n+\tif (!(reg & PHB_PCIE_DLP_TC_DL_LINKACT)) {\n+\t\t*val = 0;\n+\t\treturn OPAL_SUCCESS;\n+\t}\n+\n+\trc = phb3_pcicfg_read16(&p->phb, 0,\n+\t\t\t\tp->ecap + PCICAP_EXP_LSTAT, &state);\n+\tif (rc != OPAL_SUCCESS) {\n+\t\tPHBERR(p, \"%s: Error %lld getting link state\\n\", __func__, rc);\n \t\treturn OPAL_HARDWARE;\n-\tif (p->state != PHB3_STATE_FUNCTIONAL)\n-\t\treturn OPAL_BUSY;\n+\t}\n \n-\t/* XXX TODO - External power control ? */\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 void phb3_setup_for_link_down(struct phb3 *p)\n+static int64_t phb3_retry_state(struct pci_slot *slot)\n {\n-\tuint32_t reg32;\n-\n-\t/* Mark link down */\n-\tp->has_link = false;\n-\n-\t/* Mask PCIE port interrupts */\n-\tout_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xad42800000000000);\n-\n-\t/* Mask AER receiver error */\n-\tphb3_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, ®32);\n-\treg32 |= PCIECAP_AER_CE_RECVR_ERR;\n-\tphb3_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, reg32);\n-}\n-\n-static void phb3_setup_for_link_up(struct phb3 *p)\n-{\n-\tuint32_t reg32;\n-\t\n-\t/* Clear AER receiver error status */\n-\tphb3_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_STATUS,\n-\t\t\t PCIECAP_AER_CE_RECVR_ERR);\n-\t/* Unmask receiver error status in AER */\n-\tphb3_pcicfg_read32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, ®32);\n-\treg32 &= ~PCIECAP_AER_CE_RECVR_ERR;\n-\tphb3_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_MASK, reg32);\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n \n-\t/* Clear spurrious errors and enable PCIE port interrupts */\n-\tout_be64(p->regs + UTL_PCIE_PORT_STATUS, 0xffdfffffffffffff);\n-\tout_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xad52800000000000);\n-\n-\t/* Mark link up */\n-\tp->has_link = true;\n-\n-\t/* Don't block PCI-CFG */\n-\tp->flags &= ~PHB3_CFG_BLOCKED;\n-\n-\t/*\n-\t * For complete reset, we might be required to restore\n-\t * bus numbers for PCI bridges.\n-\t */\n-\tif (p->flags & PHB3_RESTORE_BUS_NUM) {\n-\t\tp->flags &= ~PHB3_RESTORE_BUS_NUM;\n-\t\tpci_restore_bridge_buses(&p->phb, NULL);\n-\t}\n-}\n-\n-static int64_t phb3_retry_state(struct phb3 *p)\n-{\n-\tif (p->retry_state <= PHB3_STATE_FUNCTIONAL)\n+\tif (slot->retry_state == PCI_SLOT_STATE_NORMAL)\n \t\treturn OPAL_WRONG_STATE;\n \n-\tp->delay_tgt_tb = 0;\n-\tp->state = p->retry_state;\n-\treturn p->phb.ops->poll(&p->phb);\n+\tPHBDBG(p, \"Retry state %08x\\n\", slot->retry_state);\n+\tslot->delay_tgt_tb = 0;\n+\tpci_slot_set_state(slot, slot->retry_state);\n+\tslot->retry_state = PCI_SLOT_STATE_NORMAL;\n+\treturn slot->ops.poll(slot);\n }\n \n-static int64_t phb3_sm_link_poll(struct phb3 *p)\n+static int64_t phb3_poll_link(struct pci_slot *slot)\n {\n-\tint64_t rc;\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n \tuint64_t reg;\n+\tint64_t rc;\n \n-\t/* This is the state machine to wait for the link to come\n-\t * up. Currently we just wait until we timeout, eventually\n-\t * we want to add retries and fallback to Gen1.\n-\t */\n-\tswitch(p->state) {\n-\tcase PHB3_STATE_WAIT_LINK_ELECTRICAL:\n-\t\t/* Wait for the link electrical connection to be\n+\tswitch (slot->state) {\n+\tcase PHB3_SLOT_NORMAL:\n+\tcase PHB3_SLOT_LINK_START:\n+\t\tPHBDBG(p, \"LINK: Start polling\\n\");\n+\t\tslot->retries = PHB3_LINK_ELECTRICAL_RETRIES;\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_LINK_WAIT_ELECTRICAL);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(100));\n+\tcase PHB3_SLOT_LINK_WAIT_ELECTRICAL:\n+\t\t/*\n+\t\t * Wait for the link electrical connection to be\n \t\t * established (shorter timeout). This allows us to\n \t\t * workaround spurrious presence detect on some machines\n \t\t * without waiting 10s each time\n@@ -2124,94 +2086,88 @@ static int64_t phb3_sm_link_poll(struct phb3 *p)\n \t\treg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);\n \t\tif (reg & (PHB_PCIE_DLP_INBAND_PRESENCE |\n \t\t\t PHB_PCIE_DLP_TC_DL_LINKACT)) {\n-\t\t\tPHBDBG(p, \"Electrical link detected...\\n\");\n-\t\t\tp->state = PHB3_STATE_WAIT_LINK;\n-\t\t\tp->retries = PHB3_LINK_WAIT_RETRIES;\n-\t\t} else if (p->retries-- == 0) {\n-\t\t\tPHBDBG(p, \"Timeout waiting for electrical link\\n\");\n-\t\t\tPHBDBG(p, \"DLP train control: 0x%016llx\\n\", reg);\n-\t\t\trc = phb3_retry_state(p);\n+\t\t\tPHBDBG(p, \"LINK: Electrical link detected\\n\");\n+\t\t\tpci_slot_set_state(slot, PHB3_SLOT_LINK_WAIT);\n+\t\t\tslot->retries = PHB3_LINK_WAIT_RETRIES;\n+\t\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(100));\n+\t\t}\n+\n+\t\tif (slot->retries-- == 0) {\n+\t\t\tPHBDBG(p, \"LINK: Timeout waiting for electrical link\\n\");\n+\t\t\tPHBDBG(p, \"LINK: DLP train control: 0x%016llx\\n\", reg);\n+\t\t\trc = phb3_retry_state(slot);\n \t\t\tif (rc >= OPAL_SUCCESS)\n \t\t\t\treturn rc;\n \n-\t\t\t/* No link, we still mark the PHB as functional */\n-\t\t\tp->state = PHB3_STATE_FUNCTIONAL;\n+\t\t\tpci_slot_set_state(slot, PHB3_SLOT_NORMAL);\n \t\t\treturn OPAL_SUCCESS;\n \t\t}\n-\t\treturn phb3_set_sm_timeout(p, msecs_to_tb(100));\n-\tcase PHB3_STATE_WAIT_LINK:\n-\t\t/* XXX I used the PHB_PCIE_LINK_MANAGEMENT register here but\n-\t\t * simics doesn't seem to give me anything, so I've switched\n-\t\t * to PCIE_DLP_TRAIN_CTL which appears more reliable\n-\t\t */\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(100));\n+\tcase PHB3_SLOT_LINK_WAIT:\n \t\treg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);\n \t\tif (reg & PHB_PCIE_DLP_TC_DL_LINKACT) {\n-\t\t\t/* Setup PHB for link up */\n-\t\t\tphb3_setup_for_link_up(p);\n-\t\t\tPHBDBG(p, \"Link is up!\\n\");\n-\t\t\tp->state = PHB3_STATE_FUNCTIONAL;\n+\t\t\tPHBDBG(p, \"LINK: Link is up\\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, PHB3_SLOT_NORMAL);\n \t\t\treturn OPAL_SUCCESS;\n \t\t}\n-\t\tif (p->retries-- == 0) {\n-\t\t\tPHBDBG(p, \"Timeout waiting for link up\\n\");\n-\t\t\tPHBDBG(p, \"DLP train control: 0x%016llx\\n\", reg);\n-\t\t\trc = phb3_retry_state(p);\n+\n+\t\tif (slot->retries-- == 0) {\n+\t\t\tPHBDBG(p, \"LINK: Timeout waiting for link up\\n\");\n+\t\t\tPHBDBG(p, \"LINK: DLP train control: 0x%016llx\\n\", reg);\n+\t\t\trc = phb3_retry_state(slot);\n \t\t\tif (rc >= OPAL_SUCCESS)\n \t\t\t\treturn rc;\n \n-\t\t\t/* No link, we still mark the PHB as functional */\n-\t\t\tp->state = PHB3_STATE_FUNCTIONAL;\n+\t\t\tpci_slot_set_state(slot, PHB3_SLOT_NORMAL);\n \t\t\treturn OPAL_SUCCESS;\n \t\t}\n-\t\treturn phb3_set_sm_timeout(p, msecs_to_tb(100));\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(100));\n \tdefault:\n-\t\t/* How did we get here ? */\n-\t\tassert(false);\n+\t\tPHBERR(p, \"LINK: Unexpected slot state %08x\\n\",\n+\t\t slot->state);\n \t}\n-\treturn OPAL_HARDWARE;\n-}\n \n-static int64_t phb3_start_link_poll(struct phb3 *p)\n-{\n-\t/*\n-\t * Wait for link up to 10s. However, we give up after\n-\t * only two seconds if the electrical connection isn't\n-\t * stablished according to the DLP link control register\n-\t */\n-\tp->retries = PHB3_LINK_ELECTRICAL_RETRIES;\n-\tp->state = PHB3_STATE_WAIT_LINK_ELECTRICAL;\n-\treturn phb3_set_sm_timeout(p, msecs_to_tb(100));\n+\tpci_slot_set_state(slot, PHB3_SLOT_NORMAL);\n+\treturn OPAL_HARDWARE;\n }\n \n-static int64_t phb3_sm_hot_reset(struct phb3 *p)\n+static int64_t phb3_hreset(struct pci_slot *slot)\n {\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n \tuint16_t brctl;\n-\n-\tswitch (p->state) {\n-\tcase PHB3_STATE_FUNCTIONAL:\n-\t\t/* We need do nothing with available slot */\n-\t\tif (phb3_presence_detect(&p->phb) != OPAL_SHPC_DEV_PRESENT) {\n-\t\t\tPHBDBG(p, \"Slot hreset: no device\\n\");\n-\t\t\treturn OPAL_CLOSED;\n+\tuint8_t presence = 1;\n+\n+\tswitch (slot->state) {\n+\tcase PHB3_SLOT_NORMAL:\n+\t\tPHBDBG(p, \"HRESET: Starts\\n\");\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\tPHBDBG(p, \"HRESET: No device\\n\");\n+\t\t\treturn OPAL_SUCCESS;\n \t\t}\n \n-\t\t/* Prepare for link going down */\n-\t\tphb3_setup_for_link_down(p);\n+\t\tPHBDBG(p, \"HRESET: Prepare for link down\\n\");\n+\t\tif (slot->ops.prepare_link_change)\n+\t\t\tslot->ops.prepare_link_change(slot, false);\n+\t\t/* fall through */\n+\tcase PHB3_SLOT_HRESET_START:\n+\t\tPHBDBG(p, \"HRESET: Assert\\n\");\n \n-\t\t/* Turn on hot reset */\n \t\tphb3_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);\n \t\tbrctl |= PCI_CFG_BRCTL_SECONDARY_RESET;\n \t\tphb3_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);\n-\t\tPHBDBG(p, \"Slot hreset: assert reset\\n\");\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_HRESET_DELAY);\n+\n+\t\treturn pci_slot_set_sm_timeout(slot, secs_to_tb(1));\n+\tcase PHB3_SLOT_HRESET_DELAY:\n+\t\tPHBDBG(p, \"HRESET: Deassert\\n\");\n \n-\t\tp->state = PHB3_STATE_HRESET_DELAY;\n-\t\treturn phb3_set_sm_timeout(p, secs_to_tb(1));\n-\tcase PHB3_STATE_HRESET_DELAY:\n-\t\t/* Turn off hot reset */\n \t\tphb3_pcicfg_read16(&p->phb, 0, PCI_CFG_BRCTL, &brctl);\n \t\tbrctl &= ~PCI_CFG_BRCTL_SECONDARY_RESET;\n \t\tphb3_pcicfg_write16(&p->phb, 0, PCI_CFG_BRCTL, brctl);\n-\t\tPHBDBG(p, \"Slot hreset: deassert reset\\n\");\n \n \t\t/*\n \t\t * Due to some oddball adapters bouncing the link\n@@ -2220,118 +2176,79 @@ static int64_t phb3_sm_hot_reset(struct phb3 *p)\n \t\t * we can get a spurrious link down interrupt which\n \t\t * causes us to EEH immediately.\n \t\t */\n-\t\tp->state = PHB3_STATE_HRESET_DELAY2;\n-\t\treturn phb3_set_sm_timeout(p, secs_to_tb(1));\n-\tcase PHB3_STATE_HRESET_DELAY2:\n-\t\treturn phb3_start_link_poll(p);\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_HRESET_DELAY2);\n+\t\treturn pci_slot_set_sm_timeout(slot, secs_to_tb(1));\n+\tcase PHB3_SLOT_HRESET_DELAY2:\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_LINK_START);\n+\t\treturn slot->ops.poll_link(slot);\n \tdefault:\n-\t\tPHBDBG(p, \"Slot hreset: wrong state %d\\n\", p->state);\n-\t\tbreak;\n+\t\tPHBERR(p, \"Unexpected slot state %08x\\n\", slot->state);\n \t}\n \n-\tp->state = PHB3_STATE_FUNCTIONAL;\n+\tpci_slot_set_state(slot, PHB3_SLOT_NORMAL);\n \treturn OPAL_HARDWARE;\n }\n \n-static int64_t phb3_hot_reset(struct phb *phb)\n-{\n-\tstruct phb3 *p = phb_to_phb3(phb);\n-\n-\tif (p->state != PHB3_STATE_FUNCTIONAL) {\n-\t\tPHBDBG(p, \"phb3_hot_reset: wrong state %d\\n\",\n-\t\t p->state);\n-\t\treturn OPAL_HARDWARE;\n-\t}\n-\n-\tp->flags |= PHB3_CFG_BLOCKED;\n-\treturn phb3_sm_hot_reset(p);\n-}\n-\n-static int64_t phb3_sm_fundamental_reset(struct phb3 *p)\n+static int64_t phb3_pfreset(struct pci_slot *slot)\n {\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n+\tuint8_t presence = 1;\n \tuint64_t reg;\n \n+\tswitch(slot->state) {\n+\tcase PHB3_SLOT_NORMAL:\n+\t\tPHBDBG(p, \"PFRESET: Starts\\n\");\n \n-\t/*\n-\t * Check if there's something connected. We do that here\n-\t * instead of the switch case below because we want to do\n-\t * that before we test the skip_perst\n-\t */\n-\tif (p->state == PHB3_STATE_FUNCTIONAL &&\n-\t phb3_presence_detect(&p->phb) != OPAL_SHPC_DEV_PRESENT) {\n-\t\tPHBDBG(p, \"Slot freset: no device\\n\");\n-\t\treturn OPAL_CLOSED;\n-\t}\n-\n-\t/* Handle boot time skipping of reset */\n-\tif (p->skip_perst && p->state == PHB3_STATE_FUNCTIONAL) {\n-\t\tPHBDBG(p, \"Cold boot, skipping PERST assertion\\n\");\n-\t\tp->state = PHB3_STATE_FRESET_ASSERT_DELAY;\n-\t\t/* PERST skipping happens only once */\n-\t\tp->skip_perst = false;\n-\t}\n-\n-\tswitch(p->state) {\n-\tcase PHB3_STATE_FUNCTIONAL:\n-\t\t/* Prepare for link going down */\n-\t\tphb3_setup_for_link_down(p);\n-\t\t/* Fall-through */\n-\tcase PHB3_STATE_FRESET_START:\n-\t\tif (p->state == PHB3_STATE_FRESET_START) {\n-\t\t\tPHBDBG(p, \"Slot freset: Retrying\\n\");\n-\t\t\tp->retry_state = 0;\n+\t\t/* Nothing to do without adapter connected */\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\tPHBDBG(p, \"PFRESET: No device\\n\");\n+\t\t\treturn OPAL_SUCCESS;\n \t\t}\n \n-\t\t/* Assert PERST */\n-\t\treg = in_be64(p->regs + PHB_RESET);\n-\t\treg &= ~0x2000000000000000ul;\n-\t\tout_be64(p->regs + PHB_RESET, reg);\n-\t\tPHBDBG(p, \"Slot freset: Asserting PERST\\n\");\n-\n-\t\t/* XXX Check delay for PERST... doing 1s for now */\n-\t\tp->state = PHB3_STATE_FRESET_ASSERT_DELAY;\n-\t\treturn phb3_set_sm_timeout(p, secs_to_tb(1));\n+\t\tPHBDBG(p, \"PFRESET: Prepare for link down\\n\");\n+\t\tslot->retry_state = PHB3_SLOT_PFRESET_START;\n+\t\tif (slot->ops.prepare_link_change)\n+\t\t\tslot->ops.prepare_link_change(slot, false);\n+\t\t/* fall through */\n+\tcase PHB3_SLOT_PFRESET_START:\n+\t\tif (!p->skip_perst) {\n+\t\t\tPHBDBG(p, \"PFRESET: Assert\\n\");\n+\t\t\treg = in_be64(p->regs + PHB_RESET);\n+\t\t\treg &= ~0x2000000000000000ul;\n+\t\t\tout_be64(p->regs + PHB_RESET, reg);\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tPHB3_SLOT_PFRESET_ASSERT_DELAY);\n+\t\t\treturn pci_slot_set_sm_timeout(slot, secs_to_tb(1));\n+\t\t}\n \n-\tcase PHB3_STATE_FRESET_ASSERT_DELAY:\n-\t\t/* Deassert PERST */\n+\t\t/* To skip the assert during boot time */\n+\t\tPHBDBG(p, \"PFRESET: Assert skipped\\n\");\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_PFRESET_ASSERT_DELAY);\n+\t\tp->skip_perst = false;\n+\t\t/* fall through */\n+\tcase PHB3_SLOT_PFRESET_ASSERT_DELAY:\n+\t\tPHBDBG(p, \"PFRESET: Deassert\\n\");\n \t\treg = in_be64(p->regs + PHB_RESET);\n \t\treg |= 0x2000000000000000ul;\n \t\tout_be64(p->regs + PHB_RESET, reg);\n-\t\tPHBDBG(p, \"Slot freset: Deasserting PERST\\n\");\n-\n-\t\tp->state = PHB3_STATE_FRESET_DEASSERT_DELAY;\n-\t\t/* CAPP fpga requires 1s to flash before polling link */\n-\t\treturn phb3_set_sm_timeout(p, secs_to_tb(1));\n-\n-\tcase PHB3_STATE_FRESET_DEASSERT_DELAY:\n-\t\t/* Switch to generic link poll state machine */\n-\t\treturn phb3_start_link_poll(p);\n-\n+\t\tpci_slot_set_state(slot,\n+\t\t\tPHB3_SLOT_PFRESET_DEASSERT_DELAY);\n+\n+\t\t/* CAPP FPGA requires 1s to flash before polling link */\n+\t\treturn pci_slot_set_sm_timeout(slot, secs_to_tb(1));\n+\tcase PHB3_SLOT_PFRESET_DEASSERT_DELAY:\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_HRESET_START);\n+\t\treturn slot->ops.hreset(slot);\n \tdefault:\n-\t\tPHBDBG(p, \"Slot freset: wrong state %d\\n\",\n-\t\t p->state);\n-\t\tbreak;\n+\t\tPHBERR(p, \"Unexpected slot state %08x\\n\", slot->state);\n \t}\n \n-\tp->state = PHB3_STATE_FUNCTIONAL;\n+\tpci_slot_set_state(slot, PHB3_SLOT_NORMAL);\n \treturn OPAL_HARDWARE;\n }\n \n-static int64_t phb3_fundamental_reset(struct phb *phb)\n-{\n-\tstruct phb3 *p = phb_to_phb3(phb);\n-\n-\tif (p->state != PHB3_STATE_FUNCTIONAL) {\n-\t\tPHBDBG(p, \"phb3_fundamental_reset: wrong state %d\\n\", p->state);\n-\t\treturn OPAL_HARDWARE;\n-\t}\n-\n-\t/* Allow to retry fundamental reset */\n-\tp->retry_state = PHB3_STATE_FRESET_START;\n-\tp->flags |= PHB3_CFG_BLOCKED;\n-\treturn phb3_sm_fundamental_reset(p);\n-}\n-\n struct lock capi_lock = LOCK_UNLOCKED;\n static struct {\n \tuint32_t\t\t\tec_level;\n@@ -2488,26 +2405,15 @@ static void do_capp_recovery_scoms(struct phb3 *p)\n \txscom_write(p->chip_id, CAPP_ERR_STATUS_CTRL + offset, reg);\n }\n \n-/*\n- * The OS is expected to do fundamental reset after complete\n- * reset to make sure the PHB could be recovered from the\n- * fenced state. However, the OS needn't do that explicitly\n- * since fundamental reset will be done automatically while\n- * powering on the PHB.\n- *\n- *\n- * Usually, we need power off/on the PHB. That includes the\n- * fundamental reset. However, we don't know how to control\n- * the power stuff yet. So skip that and do fundamental reset\n- * directly after reinitialization the hardware.\n- */\n-static int64_t phb3_sm_complete_reset(struct phb3 *p)\n+static int64_t phb3_creset(struct pci_slot *slot)\n {\n+\tstruct phb3 *p = phb_to_phb3(slot->phb);\n \tuint64_t cqsts, val;\n \n-\tswitch (p->state) {\n-\tcase PHB3_STATE_FENCED:\n-\tcase PHB3_STATE_FUNCTIONAL:\n+\tswitch (slot->state) {\n+\tcase PHB3_SLOT_NORMAL:\n+\tcase PHB3_SLOT_CRESET_START:\n+\t\tPHBDBG(p, \"CRESET: Starts\\n\");\n \n \t\t/* do steps 3-5 of capp recovery procedure */\n \t\tif (p->flags & PHB3_CAPP_RECOVERY)\n@@ -2536,114 +2442,92 @@ static int64_t phb3_sm_complete_reset(struct phb3 *p)\n \t\txscom_read(p->chip_id, p->spci_xscom + 1, &val);/* HW275117 */\n \t\txscom_write(p->chip_id, p->pci_xscom + 0xa,\n \t\t\t 0x8000000000000000);\n-\t\tp->state = PHB3_STATE_CRESET_WAIT_CQ;\n-\t\tp->retries = 500;\n-\t\treturn phb3_set_sm_timeout(p, msecs_to_tb(10));\n-\tcase PHB3_STATE_CRESET_WAIT_CQ:\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_CRESET_WAIT_CQ);\n+\t\tslot->retries = 500;\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(10));\n+\tcase PHB3_SLOT_CRESET_WAIT_CQ:\n \t\txscom_read(p->chip_id, p->pe_xscom + 0x1c, &val);\n \t\txscom_read(p->chip_id, p->pe_xscom + 0x1d, &val);\n \t\txscom_read(p->chip_id, p->pe_xscom + 0x1e, &val);\n \t\txscom_read(p->chip_id, p->pe_xscom + 0xf, &cqsts);\n \t\tif (!(cqsts & 0xC000000000000000)) {\n+\t\t\tPHBDBG(p, \"CRESET: No pending transactions\\n\");\n \t\t\txscom_write(p->chip_id, p->pe_xscom + 0x1, ~p->nfir_cache);\n \n-\t\t\tp->state = PHB3_STATE_CRESET_REINIT;\n-\t\t\treturn phb3_set_sm_timeout(p, msecs_to_tb(100));\n+\t\t\tpci_slot_set_state(slot, PHB3_SLOT_CRESET_REINIT);\n+\t\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(100));\n \t\t}\n \n-\t\tif (p->retries-- == 0) {\n+\t\tif (slot->retries-- == 0) {\n \t\t\tPHBERR(p, \"Timeout waiting for pending transaction\\n\");\n \t\t\tgoto error;\n \t\t}\n-\t\treturn phb3_set_sm_timeout(p, msecs_to_tb(10));\n-\tcase PHB3_STATE_CRESET_REINIT:\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(10));\n+\tcase PHB3_SLOT_CRESET_REINIT:\n+\t\tPHBDBG(p, \"CRESET: Reinitialization\\n\");\n+\n+\t\t/*\n+\t\t * Clear AIB fenced state. Otherwise, we can't access the\n+\t\t * PCI config space of root complex when reinitializing\n+\t\t * the PHB.\n+\t\t */\n \t\tp->flags &= ~PHB3_AIB_FENCED;\n \t\tp->flags &= ~PHB3_CAPP_RECOVERY;\n \t\tphb3_init_hw(p, false);\n \n-\t\tp->state = PHB3_STATE_CRESET_FRESET;\n-\t\treturn phb3_set_sm_timeout(p, msecs_to_tb(100));\n-\tcase PHB3_STATE_CRESET_FRESET:\n-\t\tp->state = PHB3_STATE_FUNCTIONAL;\n-\t\tp->flags |= PHB3_CFG_BLOCKED;\n-\t\treturn phb3_sm_fundamental_reset(p);\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_CRESET_FRESET);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(100));\n+\tcase PHB3_SLOT_CRESET_FRESET:\n+\t\tpci_slot_set_state(slot, PHB3_SLOT_NORMAL);\n+\t\treturn slot->ops.freset(slot);\n \tdefault:\n-\t\tassert(false);\n+\t\tPHBERR(p, \"CRESET: Unexpected slot state %08x\\n\",\n+\t\t slot->state);\n \t}\n \n \t/* Mark the PHB as dead and expect it to be removed */\n error:\n \tp->state = PHB3_STATE_BROKEN;\n-\treturn OPAL_PARAMETER;\n-}\n-\n-static int64_t phb3_complete_reset(struct phb *phb, uint8_t assert)\n-{\n-\tstruct phb3 *p = phb_to_phb3(phb);\n-\n-\tif ((assert == OPAL_ASSERT_RESET &&\n-\t p->state != PHB3_STATE_FUNCTIONAL &&\n-\t p->state != PHB3_STATE_FENCED) ||\n-\t (assert == OPAL_DEASSERT_RESET &&\n-\t p->state != PHB3_STATE_FUNCTIONAL)) {\n-\t\tPHBERR(p, \"phb3_creset: wrong state %d\\n\",\n-\t\t p->state);\n-\t\treturn OPAL_HARDWARE;\n-\t}\n-\n-\t/* Block PCI-CFG access */\n-\tp->flags |= PHB3_CFG_BLOCKED;\n-\n-\tif (assert == OPAL_ASSERT_RESET) {\n-\t\tPHBINF(p, \"Starting PHB reset sequence\\n\");\n-\t\treturn phb3_sm_complete_reset(p);\n-\t} else {\n-\t\t/* Restore bus numbers for bridges */\n-\t\tp->flags |= PHB3_RESTORE_BUS_NUM;\n-\n-\t\treturn phb3_sm_hot_reset(p);\n-\t}\n+\treturn OPAL_HARDWARE;\n }\n \n-static int64_t phb3_poll(struct phb *phb)\n+/*\n+ * Initialize root complex slot, which is mainly used to\n+ * do fundamental reset before PCI enumeration in PCI core.\n+ * When probing root complex and building its real slot,\n+ * the operations will be copied over.\n+ */\n+static struct pci_slot *phb3_slot_create(struct phb *phb)\n {\n-\tstruct phb3 *p = phb_to_phb3(phb);\n-\tuint64_t now = mftb();\n+\tstruct pci_slot *slot;\n \n-\tif (p->state == PHB3_STATE_FUNCTIONAL)\n-\t\treturn OPAL_SUCCESS;\n+\tslot = pci_slot_alloc(phb, NULL);\n+\tif (!slot)\n+\t\treturn slot;\n \n-\t/* Check timer */\n-\tif (p->delay_tgt_tb &&\n-\t tb_compare(now, p->delay_tgt_tb) == TB_ABEFOREB)\n-\t\treturn p->delay_tgt_tb - now;\n-\n-\t/* Expired (or not armed), clear it */\n-\tp->delay_tgt_tb = 0;\n-\n-\t/* Dispatch to the right state machine */\n-\tswitch(p->state) {\n-\tcase PHB3_STATE_HRESET_DELAY:\n-\tcase PHB3_STATE_HRESET_DELAY2:\n-\t\treturn phb3_sm_hot_reset(p);\n-\tcase PHB3_STATE_FRESET_START:\n-\tcase PHB3_STATE_FRESET_ASSERT_DELAY:\n-\tcase PHB3_STATE_FRESET_DEASSERT_DELAY:\n-\t\treturn phb3_sm_fundamental_reset(p);\n-\tcase PHB3_STATE_CRESET_WAIT_CQ:\n-\tcase PHB3_STATE_CRESET_REINIT:\n-\tcase PHB3_STATE_CRESET_FRESET:\n-\t\treturn phb3_sm_complete_reset(p);\n-\tcase PHB3_STATE_WAIT_LINK_ELECTRICAL:\n-\tcase PHB3_STATE_WAIT_LINK:\n-\t\treturn phb3_sm_link_poll(p);\n-\tdefault:\n-\t\tPHBDBG(p, \"phb3_poll: wrong state %d\\n\", p->state);\n-\t\tbreak;\n-\t}\n+\t/* Elementary functions */\n+\tslot->ops.get_presence_state = phb3_get_presence_state;\n+\tslot->ops.get_link_state = phb3_get_link_state;\n+\tslot->ops.get_power_state = NULL;\n+\tslot->ops.get_attention_state = NULL;\n+\tslot->ops.get_latch_state = NULL;\n+\tslot->ops.set_power_state = NULL;\n+\tslot->ops.set_attention_state = NULL;\n \n-\t/* Unknown state, could be a HW error */\n-\treturn OPAL_HARDWARE;\n+\t/*\n+\t * For PHB slots, we have to split the fundamental reset\n+\t * into 2 steps. We might not have the first step which\n+\t * is to power off/on the slot, or it's controlled by\n+\t * individual platforms.\n+\t */\n+\tslot->ops.prepare_link_change\t= phb3_prepare_link_change;\n+\tslot->ops.poll_link\t\t= phb3_poll_link;\n+\tslot->ops.hreset\t\t= phb3_hreset;\n+\tslot->ops.freset\t\t= phb3_pfreset;\n+\tslot->ops.pfreset\t\t= phb3_pfreset;\n+\tslot->ops.creset\t\t= phb3_creset;\n+\n+\treturn slot;\n }\n \n static int64_t phb3_eeh_freeze_status(struct phb *phb, uint64_t pe_number,\n@@ -3581,7 +3465,6 @@ static const struct phb_ops phb3_ops = {\n \t.choose_bus\t\t= phb3_choose_bus,\n \t.get_reserved_pe_number\t= phb3_get_reserved_pe_number,\n \t.device_init\t\t= phb3_device_init,\n-\t.presence_detect\t= phb3_presence_detect,\n \t.ioda_reset\t\t= phb3_ioda_reset,\n \t.papr_errinjct_reset\t= phb3_papr_errinjct_reset,\n \t.pci_reinit\t\t= phb3_pci_reinit,\n@@ -3596,14 +3479,6 @@ static const struct phb_ops phb3_ops = {\n \t.get_msi_64\t\t= phb3_get_msi_64,\n \t.set_pe\t\t\t= phb3_set_pe,\n \t.set_peltv\t\t= phb3_set_peltv,\n-\t.link_state\t\t= phb3_link_state,\n-\t.power_state\t\t= phb3_power_state,\n-\t.slot_power_off\t\t= phb3_slot_power_off,\n-\t.slot_power_on\t\t= phb3_slot_power_on,\n-\t.hot_reset\t\t= phb3_hot_reset,\n-\t.fundamental_reset\t= phb3_fundamental_reset,\n-\t.complete_reset\t\t= phb3_complete_reset,\n-\t.poll\t\t\t= phb3_poll,\n \t.eeh_freeze_status\t= phb3_eeh_freeze_status,\n \t.eeh_freeze_clear\t= phb3_eeh_freeze_clear,\n \t.eeh_freeze_set\t\t= phb3_eeh_freeze_set,\n@@ -4393,6 +4268,7 @@ static void phb3_create(struct dt_node *np)\n {\n \tconst struct dt_property *prop;\n \tstruct phb3 *p = zalloc(sizeof(struct phb3));\n+\tstruct pci_slot *slot;\n \tsize_t lane_eq_len;\n \tstruct dt_node *iplp;\n \tstruct proc_chip *chip;\n@@ -4458,6 +4334,9 @@ static void phb3_create(struct dt_node *np)\n \telse\n \t\topal_id = p->chip_id * 4 + p->index;\n \tpci_register_phb(&p->phb, opal_id);\n+\tslot = phb3_slot_create(&p->phb);\n+\tif (!slot)\n+\t\tPHBERR(p, \"Cannot create PHB slot\\n\");\n \n \t/* Hello ! */\n \tpath = dt_get_path(np);\ndiff --git a/include/phb3.h b/include/phb3.h\nindex 9a045c0..cf4b910 100644\n--- a/include/phb3.h\n+++ b/include/phb3.h\n@@ -204,27 +204,35 @@ enum phb3_state {\n \n \t/* Normal PHB functional state */\n \tPHB3_STATE_FUNCTIONAL,\n-\n-\t/* Hot reset */\n-\tPHB3_STATE_HRESET_DELAY,\n-\tPHB3_STATE_HRESET_DELAY2,\n-\n-\t/* Fundamental reset */\n-\tPHB3_STATE_FRESET_START,\n-\tPHB3_STATE_FRESET_ASSERT_DELAY,\n-\tPHB3_STATE_FRESET_DEASSERT_DELAY,\n-\n-\t/* Complete reset */\n-\tPHB3_STATE_CRESET_WAIT_CQ,\n-\tPHB3_STATE_CRESET_REINIT,\n-\tPHB3_STATE_CRESET_FRESET,\n-\n-\t/* Link state machine */\n-\tPHB3_STATE_WAIT_LINK_ELECTRICAL,\n-\tPHB3_STATE_WAIT_LINK,\n };\n \n /*\n+ * PHB3 PCI slot state. When you're going to apply any\n+ * changes here, please make sure the base state isn't\n+ * conflicting with those defined in pci-slot.h\n+ */\n+#define PHB3_SLOT_NORMAL\t\t\t0x00000000\n+#define PHB3_SLOT_LINK\t\t\t\t0x00000100\n+#define PHB3_SLOT_LINK_START\t\t\t0x00000101\n+#define PHB3_SLOT_LINK_WAIT_ELECTRICAL\t0x00000102\n+#define PHB3_SLOT_LINK_WAIT\t\t\t0x00000103\n+#define PHB3_SLOT_HRESET\t\t\t0x00000200\n+#define PHB3_SLOT_HRESET_START\t\t0x00000201\n+#define PHB3_SLOT_HRESET_DELAY\t\t0x00000202\n+#define PHB3_SLOT_HRESET_DELAY2\t\t0x00000203\n+#define PHB3_SLOT_FRESET\t\t\t0x00000300\n+#define PHB3_SLOT_FRESET_START\t\t0x00000301\n+#define PHB3_SLOT_PFRESET\t\t\t0x00000400\n+#define PHB3_SLOT_PFRESET_START\t\t0x00000401\n+#define PHB3_SLOT_PFRESET_ASSERT_DELAY\t0x00000402\n+#define PHB3_SLOT_PFRESET_DEASSERT_DELAY\t0x00000403\n+#define PHB3_SLOT_CRESET\t\t\t0x00000500\n+#define PHB3_SLOT_CRESET_START\t\t0x00000501\n+#define PHB3_SLOT_CRESET_WAIT_CQ\t\t0x00000502\n+#define PHB3_SLOT_CRESET_REINIT\t\t0x00000503\n+#define PHB3_SLOT_CRESET_FRESET\t\t0x00000504\n+\n+/*\n * PHB3 error descriptor. Errors from all components (PBCQ, PHB)\n * will be cached to PHB3 instance. However, PBCQ errors would\n * have higher priority than those from PHB\n@@ -254,13 +262,13 @@ struct phb3_err {\n #define PHB3_AIB_FENCED\t\t0x00000001\n #define PHB3_CFG_USE_ASB\t0x00000002\n #define PHB3_CFG_BLOCKED\t0x00000004\n-#define PHB3_RESTORE_BUS_NUM\t0x00000008\n-#define PHB3_CAPP_RECOVERY\t0x00000010\n+#define PHB3_CAPP_RECOVERY\t0x00000008\n \n struct phb3 {\n \tunsigned int\t\tindex;\t /* 0..2 index inside P8 */\n \tunsigned int\t\tflags;\n \tunsigned int\t\tchip_id; /* Chip ID (== GCID on P8) */\n+\tenum phb3_state\t\tstate;\n \tunsigned int\t\trev; /* 00MMmmmm */\n #define PHB3_REV_MURANO_DD10\t0xa30001\n #define PHB3_REV_VENICE_DD10\t0xa30002\n@@ -288,10 +296,6 @@ struct phb3 {\n \n \tbool\t\t\tskip_perst; /* Skip first perst */\n \tbool\t\t\thas_link;\n-\tenum phb3_state\t\tstate;\n-\tenum phb3_state\t\tretry_state;\n-\tuint64_t\t\tdelay_tgt_tb;\n-\tuint64_t\t\tretries;\n \tint64_t\t\t\tecap;\t /* cached PCI-E cap offset */\n \tint64_t\t\t\taercap;\t /* cached AER ecap offset */\n \tconst __be64\t\t*lane_eq;\n", "prefixes": [ "v12", "16/23" ] }