Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/633519/?format=api
{ "id": 633519, "url": "http://patchwork.ozlabs.org/api/patches/633519/?format=api", "web_url": "http://patchwork.ozlabs.org/project/skiboot/patch/1465535032-26749-19-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-19-git-send-email-gwshan@linux.vnet.ibm.com>", "list_archive_url": null, "date": "2016-06-10T05:03:47", "name": "[v12,18/23] platforms/ibm-fsp: Support PCI slot", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "3146c8f1bcea4463d2f376bc9b05fa9fadd59dc7", "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-19-git-send-email-gwshan@linux.vnet.ibm.com/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/633519/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/633519/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 3rQqtQ753Bz9sD3\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Jun 2016 15:07:42 +1000 (AEST)", "from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3rQqtQ6M3CzDqHm\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Jun 2016 15:07:42 +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 3rQqrJ60yXzDqNn\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:52 +1000 (AEST)", "from pps.filterd (m0049461.ppops.net [127.0.0.1])\n\tby mx0b-001b2d01.pphosted.com (8.16.0.11/8.16.0.11) with SMTP id\n\tu5A541DR013785\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 01:05:50 -0400", "from e23smtp01.au.ibm.com (e23smtp01.au.ibm.com [202.81.31.143])\n\tby mx0b-001b2d01.pphosted.com with ESMTP id 23fa5xy7yb-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:49 -0400", "from localhost\n\tby e23smtp01.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:46 +1000", "from d23dlp01.au.ibm.com (202.81.31.203)\n\tby e23smtp01.au.ibm.com (202.81.31.207) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tFri, 10 Jun 2016 15:05:45 +1000", "from d23relay10.au.ibm.com (d23relay10.au.ibm.com [9.190.26.77])\n\tby d23dlp01.au.ibm.com (Postfix) with ESMTP id 03AE92CE8057\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:35 +1000 (EST)", "from d23av03.au.ibm.com (d23av03.au.ibm.com [9.190.234.97])\n\tby d23relay10.au.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id\n\tu5A55TYp8913366\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:29 +1000", "from d23av03.au.ibm.com (localhost [127.0.0.1])\n\tby d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVout) with ESMTP id\n\tu5A55ToE025769\n\tfor <skiboot@lists.ozlabs.org>; Fri, 10 Jun 2016 15:05:29 +1000", "from ozlabs.au.ibm.com (ozlabs.au.ibm.com [9.192.253.14])\n\tby d23av03.au.ibm.com (8.14.4/8.14.4/NCO v10.0 AVin) with ESMTP id\n\tu5A55THi025643; Fri, 10 Jun 2016 15:05:29 +1000", "from bran.ozlabs.ibm.com (haven.au.ibm.com [9.192.254.114])\n\tby ozlabs.au.ibm.com (Postfix) with ESMTP id 41027A0216;\n\tFri, 10 Jun 2016 15:03:59 +1000 (AEST)", "from gwshan (shangw.ozlabs.ibm.com [10.61.2.199])\n\tby bran.ozlabs.ibm.com (Postfix) with ESMTP id 3E1E1E3B1A;\n\tFri, 10 Jun 2016 15:03:59 +1000 (AEST)", "by gwshan (Postfix, from userid 1000)\n\tid 222EE942CA3; Fri, 10 Jun 2016 15:03:59 +1000 (AEST)" ], "X-IBM-Helo": "d23dlp01.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:47 +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-1617-0000-0000-0000012AC837", "X-IBM-AV-DETECTION": "SAVI=unused REMOTE=unused XFE=unused", "x-cbparentid": "16061005-1618-0000-0000-0000460A8C6C", "Message-Id": "<1465535032-26749-19-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 18/23] platforms/ibm-fsp: 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": "The patch reworks PCI stuff for IBM's Apollo and Firenze platforms to\nsupport PCI slot:\n\n * Platform shared PCI slot is represented by \"struct lxvpd_pci_slot\"\n for Apollo and Firenze. The information of that is fetched from\n VPD.\n * Apollo platform uses \"struct lxvpd_pci_slot\" as its platform slot,\n while Firenze platform uses \"struct firenze_pci_slot\" as its\n platform slot in order to support external I2C-based PCI slot power\n maangement as well as PERST supported by the downstream ports of\n particular PLX PCIe switches.\n * On Firenze platform, the properties and methods to manage PHB slot\n might be overrided to utilize the capability of external power\n management.\n\nSigned-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>\n---\n platforms/ibm-fsp/Makefile.inc | 3 +-\n platforms/ibm-fsp/apollo-pci.c | 94 ++++\n platforms/ibm-fsp/apollo.c | 23 +-\n platforms/ibm-fsp/firenze-pci.c | 957 ++++++++++++++++++++++++++++++++++++++++\n platforms/ibm-fsp/firenze.c | 345 +--------------\n platforms/ibm-fsp/ibm-fsp.h | 13 +\n platforms/ibm-fsp/lxvpd.c | 374 +++++++++-------\n platforms/ibm-fsp/lxvpd.h | 35 +-\n 8 files changed, 1321 insertions(+), 523 deletions(-)\n create mode 100644 platforms/ibm-fsp/apollo-pci.c\n create mode 100644 platforms/ibm-fsp/firenze-pci.c", "diff": "diff --git a/platforms/ibm-fsp/Makefile.inc b/platforms/ibm-fsp/Makefile.inc\nindex a885cbb..c5bec84 100644\n--- a/platforms/ibm-fsp/Makefile.inc\n+++ b/platforms/ibm-fsp/Makefile.inc\n@@ -1,6 +1,7 @@\n SUBDIRS += $(PLATDIR)/ibm-fsp\n \n-IBM_FSP_OBJS = common.o lxvpd.o apollo.o firenze.o\n+IBM_FSP_OBJS = common.o lxvpd.o apollo.o apollo-pci.o \\\n+\t firenze.o firenze-pci.o\n IBM_FSP = $(PLATDIR)/ibm-fsp/built-in.o\n $(IBM_FSP): $(IBM_FSP_OBJS:%=$(PLATDIR)/ibm-fsp/%)\n \ndiff --git a/platforms/ibm-fsp/apollo-pci.c b/platforms/ibm-fsp/apollo-pci.c\nnew file mode 100644\nindex 0000000..f13b69d\n--- /dev/null\n+++ b/platforms/ibm-fsp/apollo-pci.c\n@@ -0,0 +1,94 @@\n+/* Copyright 2013-2015 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 <device.h>\n+#include <fsp.h>\n+#include <p7ioc.h>\n+#include <pci-cfg.h>\n+#include <pci.h>\n+#include <pci-slot.h>\n+\n+#include \"ibm-fsp.h\"\n+#include \"lxvpd.h\"\n+\n+/* Debugging option */\n+#define APOLLO_PCI_DBG(fmt, a...)\t\\\n+\tprlog(PR_DEBUG, \"APOLLO-PCI: \" fmt, ##a)\n+#define APOLLO_PCI_INFO(fmt, a...)\t\\\n+\tprlog(PR_INFO, \"APOLLO-PCI: \" fmt, ##a)\n+#define APOLLO_PCI_ERR(fmt, a...)\t\\\n+\tprlog(PR_ERR, \"APOLLO-PCI: \" fmt, ##a)\n+\n+void apollo_pci_setup_phb(struct phb *phb, unsigned int index)\n+{\n+\tstruct dt_node *ioc_node;\n+\tstruct lxvpd_pci_slot *s = NULL;\n+\tstruct pci_slot *slot = NULL;\n+\n+\t/* Grab the device-tree node of the IOC */\n+\tioc_node = phb->dt_node->parent;\n+\tif (!ioc_node) {\n+\t\tAPOLLO_PCI_DBG(\"No IOC devnode for PHB%04x\\n\",\n+\t\t\t phb->opal_id);\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * Process the pcie slot entries from the lx vpd lid\n+\t *\n+\t * FIXME: We currently assume chip 1 always, this will have to be\n+\t * fixed once we understand the right way to get the BRxy/BRxy \"x\"\n+\t * \"x\" value. It's not working well. I found 2 different root ports\n+\t * on Firebird-L has been assigned to same slot label.\n+\t */\n+\tlxvpd_process_slot_entries(phb, ioc_node, 1,\n+\t\t\t\t index, sizeof(struct lxvpd_pci_slot));\n+\n+\t/* Fixup P7IOC PHB slot */\n+\tslot = phb->slot;\n+\ts = slot ? lxvpd_get_slot(slot) : NULL;\n+\tif (s)\n+\t\tlxvpd_extract_info(slot, s);\n+}\n+\n+void apollo_pci_get_slot_info(struct phb *phb, struct pci_device *pd)\n+{\n+\tstruct pci_slot *slot;\n+\tstruct lxvpd_pci_slot *s = NULL;\n+\n+\tif (pd->dev_type != PCIE_TYPE_ROOT_PORT &&\n+\t pd->dev_type != PCIE_TYPE_SWITCH_UPPORT &&\n+\t pd->dev_type != PCIE_TYPE_SWITCH_DNPORT &&\n+\t pd->dev_type != PCIE_TYPE_PCIE_TO_PCIX)\n+\t\treturn;\n+\n+\t/* Create PCIe slot */\n+\tslot = pcie_slot_create(phb, pd);\n+\tif (!slot)\n+\t\treturn;\n+\n+\t/* Root complex inherits methods from PHB slot */\n+\tif (!pd->parent && phb->slot)\n+\t\tmemcpy(&slot->ops, &phb->slot->ops, sizeof(struct pci_slot_ops));\n+\n+\t/* Patch PCIe slot */\n+\ts = lxvpd_get_slot(slot);\n+\tif (s) {\n+\t\tlxvpd_extract_info(slot, s);\n+\t\tslot->ops.add_properties = lxvpd_add_slot_properties;\n+\t}\n+}\ndiff --git a/platforms/ibm-fsp/apollo.c b/platforms/ibm-fsp/apollo.c\nindex e9616d5..d98699d 100644\n--- a/platforms/ibm-fsp/apollo.c\n+++ b/platforms/ibm-fsp/apollo.c\n@@ -19,6 +19,7 @@\n #include <device.h>\n #include <fsp.h>\n #include <pci.h>\n+#include <pci-slot.h>\n \n #include \"ibm-fsp.h\"\n #include \"lxvpd.h\"\n@@ -28,24 +29,6 @@ static bool apollo_probe(void)\n \treturn dt_node_is_compatible(dt_root, \"ibm,apollo\");\n }\n \n-static void apollo_setup_phb(struct phb *phb, unsigned int index)\n-{\n-\tstruct dt_node *ioc_node;\n-\n-\t/* Grab the device-tree node of the IOC */\n-\tioc_node = phb->dt_node->parent;\n-\tif (!ioc_node)\n-\t\treturn;\n-\n-\t/*\n-\t * Process the pcie slot entries from the lx vpd lid\n-\t *\n-\t * FIXME: We currently assume chip 1 always, this will have to be\n-\t * fixed once we understand the right way to get the BRxy/BRxy \"x\"\n-\t * \"x\" value. (this actually seems to work...)\n-\t */\n-\tlxvpd_process_slot_entries(phb, ioc_node, 1, index);\n-}\n \n DECLARE_PLATFORM(apollo) = {\n \t.name\t\t\t= \"Apollo\",\n@@ -54,8 +37,8 @@ DECLARE_PLATFORM(apollo) = {\n \t.exit\t\t\t= ibm_fsp_exit,\n \t.cec_power_down\t\t= ibm_fsp_cec_power_down,\n \t.cec_reboot\t\t= ibm_fsp_cec_reboot,\n-\t.pci_setup_phb\t\t= apollo_setup_phb,\n-\t.pci_get_slot_info\t= lxvpd_get_slot_info,\n+\t.pci_setup_phb\t\t= apollo_pci_setup_phb,\n+\t.pci_get_slot_info\t= apollo_pci_get_slot_info,\n \t.nvram_info\t\t= fsp_nvram_info,\n \t.nvram_start_read\t= fsp_nvram_start_read,\n \t.nvram_write\t\t= fsp_nvram_write,\ndiff --git a/platforms/ibm-fsp/firenze-pci.c b/platforms/ibm-fsp/firenze-pci.c\nnew file mode 100644\nindex 0000000..a72951a\n--- /dev/null\n+++ b/platforms/ibm-fsp/firenze-pci.c\n@@ -0,0 +1,957 @@\n+/* Copyright 2013-2015 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 <device.h>\n+#include <fsp.h>\n+#include <lock.h>\n+#include <timer.h>\n+#include <xscom.h>\n+#include <pci-cfg.h>\n+#include <pci.h>\n+#include <pci-slot.h>\n+#include <phb3.h>\n+#include <chip.h>\n+#include <i2c.h>\n+\n+#include \"ibm-fsp.h\"\n+#include \"lxvpd.h\"\n+\n+/* Debugging options */\n+#define FIRENZE_PCI_DBG(fmt, a...)\t\\\n+\tprlog(PR_DEBUG, \"FIRENZE-PCI: \" fmt, ##a)\n+#define FIRENZE_PCI_INFO(fmt, a...)\t\\\n+\tprlog(PR_INFO, \"FIRENZE-PCI: \" fmt, ##a)\n+#define FIRENZE_PCI_ERR(fmt, a...)\t\\\n+\tprlog(PR_ERR, \"FIRENZE-PCI: \" fmt, ##a)\n+\n+/* Dump PCI slots before sending to FSP */\n+#define FIRENZE_PCI_INVENTORY_DUMP\n+\n+/*\n+ * Firenze PCI slot states to override the default set.\n+ * Refer to pci-slot.h for the default PCI state set\n+ * when you're going to change below values.\n+ */\n+#define FIRENZE_PCI_SLOT_NORMAL\t\t\t0x00000000\n+#define FIRENZE_PCI_SLOT_HRESET\t\t\t0x00000200\n+#define FIRENZE_PCI_SLOT_HRESET_START\t\t0x00000201\n+#define FIRENZE_PCI_SLOT_FRESET\t\t\t0x00000300\n+#define FIRENZE_PCI_SLOT_FRESET_START\t\t0x00000301\n+#define FIRENZE_PCI_SLOT_FRESET_WAIT_RSP\t0x00000302\n+#define FIRENZE_PCI_SLOT_FRESET_DELAY\t\t0x00000303\n+#define FIRENZE_PCI_SLOT_FRESET_POWER_STATE\t0x00000304\n+#define FIRENZE_PCI_SLOT_FRESET_POWER_OFF\t0x00000305\n+#define FIRENZE_PCI_SLOT_FRESET_POWER_ON\t0x00000306\n+#define FIRENZE_PCI_SLOT_PERST_DEASSERT\t0x00000307\n+#define FIRENZE_PCI_SLOT_PERST_DELAY\t\t0x00000308\n+#define FIRENZE_PCI_SLOT_PFRESET\t\t0x00000400\n+#define FIRENZE_PCI_SLOT_PFRESET_START\t0x00000401\n+#define FIRENZE_PCI_SLOT_GPOWER\t\t\t0x00000600\n+#define FIRENZE_PCI_SLOT_GPOWER_START\t\t0x00000601\n+#define FIRENZE_PCI_SLOT_SPOWER\t\t\t0x00000700\n+#define FIRENZE_PCI_SLOT_SPOWER_START\t\t0x00000701\n+#define FIRENZE_PCI_SLOT_SPOWER_DONE\t\t0x00000702\n+\n+/* Timeout for power status */\n+#define FIRENZE_PCI_SLOT_RETRIES\t500\n+#define FIRENZE_PCI_SLOT_DELAY\t\t10\t/* ms */\n+#define FIRENZE_PCI_I2C_TIMEOUT\t\t500\t/* ms */\n+\n+/*\n+ * Need figure out more stuff later: LED and presence\n+ * detection sensors are accessed from PSI/FSP.\n+ */\n+struct firenze_pci_slot {\n+\tstruct lxvpd_pci_slot\tlxvpd_slot;\t/* LXVPD slot data */\n+\n+\t/* Next slot state */\n+\tuint32_t\t\tnext_state;\n+\n+\t/* Power management */\n+\tstruct i2c_bus\t\t*i2c_bus;\t/* Where MAX5961 seats */\n+\tstruct i2c_request\t*req;\t\t/* I2C request message */\n+\tuint8_t\t\t\ti2c_rw_buf[8];\t/* I2C read/write buffer */\n+\tuint8_t\t\t\tpower_mask;\t/* Bits for power status */\n+\tuint8_t\t\t\tpower_on;\t/* Bits for power on */\n+\tuint8_t\t\t\tpower_off;\t/* Bits for power off */\n+\tuint8_t\t\t\t*power_status;\t/* Last power status */\n+\tuint16_t\t\tperst_reg;\t/* PERST config register */\n+\tuint16_t\t\tperst_bit;\t/* PERST bit */\n+};\n+\n+struct firenze_pci_slot_info {\n+\tuint8_t\t\tindex;\n+\tconst char\t*label;\n+\tuint8_t\t\texternal_power_mgt;\n+\tuint8_t\t\tinband_perst;\n+\tuint8_t\t\tchip_id;\n+\tuint8_t\t\tmaster_id;\n+\tuint8_t\t\tport_id;\n+\tuint8_t\t\tslave_addr;\n+\tuint8_t\t\tchannel;\n+\tuint8_t\t\tpower_status;\n+\tuint8_t\t\tbuddy;\n+};\n+\n+struct firenze_pci_inv {\n+\tuint32_t\thw_proc_id;\n+\tuint16_t\tslot_idx;\n+\tuint16_t\treserved;\n+\tuint16_t\tvendor_id;\n+\tuint16_t\tdevice_id;\n+\tuint16_t\tsubsys_vendor_id;\n+\tuint16_t\tsubsys_device_id;\n+};\n+\n+struct firenze_pci_inv_data {\n+\tuint32_t version;\t/* currently 1 */\n+\tuint32_t num_entries;\n+\tuint32_t entry_size;\n+\tuint32_t entry_offset;\n+\tstruct firenze_pci_inv\tentries[];\n+};\n+\n+/*\n+ * Note: According to Tuleta system workbook, I didn't figure\n+ * out the I2C mapping info for slot C14/C15.\n+ */\n+static struct firenze_pci_inv_data *firenze_inv_data;\n+static uint32_t firenze_inv_cnt;\n+static struct firenze_pci_slot_info firenze_pci_slots[] = {\n+\t{ 0x0B, \"C7\", 1, 1, 0, 1, 0, 0x35, 1, 0xAA, 0 },\n+\t{ 0x11, \"C14\", 0, 1, 0, 0, 0, 0x00, 0, 0xAA, 1 },\n+\t{ 0x0F, \"C11\", 1, 1, 0, 1, 0, 0x32, 1, 0xAA, 2 },\n+\t{ 0x10, \"C12\", 1, 1, 0, 1, 0, 0x39, 0, 0xAA, 3 },\n+\t{ 0x0A, \"C6\", 1, 1, 0, 1, 0, 0x35, 0, 0xAA, 0 },\n+\t{ 0x12, \"C15\", 0, 1, 0, 0, 0, 0x00, 0, 0xAA, 5 },\n+\t{ 0x01, \"USB\", 0, 0, 0, 0, 0, 0x00, 0, 0xAA, 6 },\n+\t{ 0x0C, \"C8\", 1, 1, 0, 1, 0, 0x36, 0, 0xAA, 7 },\n+\t{ 0x0D, \"C9\", 1, 1, 0, 1, 0, 0x36, 1, 0xAA, 7 },\n+\t{ 0x0E, \"C10\", 1, 1, 0, 1, 0, 0x32, 0, 0xAA, 2 },\n+\t{ 0x09, \"C5\", 1, 1, 0x10, 1, 0, 0x39, 1, 0xAA, 10 },\n+\t{ 0x08, \"C4\", 1, 1, 0x10, 1, 0, 0x39, 0, 0xAA, 10 },\n+\t{ 0x07, \"C3\", 1, 1, 0x10, 1, 0, 0x3A, 1, 0xAA, 12 },\n+\t{ 0x06, \"C2\", 1, 1, 0x10, 1, 0, 0x3A, 0, 0xAA, 12 }\n+};\n+\n+static void firenze_pci_add_inventory(struct phb *phb,\n+\t\t\t\t struct pci_device *pd)\n+{\n+\tstruct lxvpd_pci_slot *lxvpd_slot;\n+\tstruct firenze_pci_inv *entry;\n+\tstruct proc_chip *chip;\n+\tsize_t size;\n+\tbool need_init = false;\n+\n+\t/*\n+\t * Do we need to add that to the FSP inventory for power\n+\t * management?\n+\t *\n+\t * For now, we only add devices that:\n+\t *\n+\t * - Are function 0\n+\t * - Are not an RC or a downstream bridge\n+\t * - Have a direct parent that has a slot entry\n+\t * - Slot entry says pluggable\n+\t * - Aren't an upstream switch that has slot info\n+\t */\n+\tif (!pd || !pd->parent)\n+\t\treturn;\n+\tif (pd->bdfn & 7)\n+\t\treturn;\n+\tif (pd->dev_type == PCIE_TYPE_ROOT_PORT ||\n+\t pd->dev_type == PCIE_TYPE_SWITCH_DNPORT)\n+\t\treturn;\n+\tif (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT &&\n+\t pd->slot && pd->slot->data)\n+\t\treturn;\n+\tif (!pd->parent->slot ||\n+\t !pd->parent->slot->data)\n+\t\treturn;\n+\tlxvpd_slot = pd->parent->slot->data;\n+\tif (!lxvpd_slot->pluggable)\n+\t\treturn;\n+\n+\t/* Check if we need to do some (Re)allocation */\n+\tif (!firenze_inv_data ||\n+ firenze_inv_data->num_entries == firenze_inv_cnt) {\n+\t\tneed_init = !firenze_inv_data;\n+\n+\t\t/* (Re)allocate the block to the new size */\n+\t\tfirenze_inv_cnt += 4;\n+\t\tsize = sizeof(struct firenze_pci_inv_data) +\n+\t\t sizeof(struct firenze_pci_inv) * firenze_inv_cnt;\n+ firenze_inv_data = realloc(firenze_inv_data, size);\n+\t}\n+\n+\t/* Initialize the header for a new inventory */\n+\tif (need_init) {\n+\t\tfirenze_inv_data->version = 1;\n+\t\tfirenze_inv_data->num_entries = 0;\n+\t\tfirenze_inv_data->entry_size =\n+\t\t\tsizeof(struct firenze_pci_inv);\n+\t\tfirenze_inv_data->entry_offset =\n+\t\t\toffsetof(struct firenze_pci_inv_data, entries);\n+\t}\n+\n+\t/* Append slot entry */\n+\tentry = &firenze_inv_data->entries[firenze_inv_data->num_entries++];\n+\tchip = get_chip(dt_get_chip_id(phb->dt_node));\n+\tif (!chip) {\n+\t\tFIRENZE_PCI_ERR(\"No chip device node for PHB%04x\\n\",\n+\t\t\t\tphb->opal_id);\n+ return;\n+\t}\n+\n+\tentry->hw_proc_id = chip->pcid;\n+\tentry->reserved = 0;\n+\tif (pd->parent &&\n+\t pd->parent->slot &&\n+\t pd->parent->slot->data) {\n+\t\tlxvpd_slot = pd->parent->slot->data;\n+\t\tentry->slot_idx = lxvpd_slot->slot_index;\n+\t}\n+\n+\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_VENDOR_ID, &entry->vendor_id);\n+\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_DEVICE_ID, &entry->device_id);\n+ if (pd->is_bridge) {\n+ int64_t ssvc = pci_find_cap(phb, pd->bdfn,\n+\t\t\t\t\t PCI_CFG_CAP_ID_SUBSYS_VID);\n+\t\tif (ssvc <= 0) {\n+\t\t\tentry->subsys_vendor_id = 0xffff;\n+\t\t\tentry->subsys_device_id = 0xffff;\n+\t\t} else {\n+\t\t\tpci_cfg_read16(phb, pd->bdfn,\n+\t\t\t\t ssvc + PCICAP_SUBSYS_VID_VENDOR,\n+\t\t\t\t &entry->subsys_vendor_id);\n+\t\t\tpci_cfg_read16(phb, pd->bdfn,\n+\t\t\t\t ssvc + PCICAP_SUBSYS_VID_DEVICE,\n+\t\t\t\t &entry->subsys_device_id);\n+\t\t}\n+ } else {\n+\t\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_VENDOR_ID,\n+\t\t\t &entry->subsys_vendor_id);\n+\t\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_ID,\n+\t\t\t &entry->subsys_device_id);\n+\t}\n+}\n+\n+static void firenze_dump_pci_inventory(void)\n+{\n+#ifdef FIRENZE_PCI_INVENTORY_DUMP\n+\tstruct firenze_pci_inv *e;\n+\tuint32_t i;\n+\n+\tif (!firenze_inv_data)\n+\t\treturn;\n+\n+\tFIRENZE_PCI_INFO(\"Dumping Firenze PCI inventory\\n\");\n+\tFIRENZE_PCI_INFO(\"HWP SLT VDID DVID SVID SDID\\n\");\n+\tFIRENZE_PCI_INFO(\"---------------------------\\n\");\n+\tfor (i = 0; i < firenze_inv_data->num_entries; i++) {\n+\t\te = &firenze_inv_data->entries[i];\n+\n+\t\tFIRENZE_PCI_INFO(\"%03d %03d %04x %04x %04x %04x\\n\",\n+\t\t\t\t e->hw_proc_id, e->slot_idx,\n+\t\t\t\t e->vendor_id, e->device_id,\n+\t\t\t\t e->subsys_vendor_id, e->subsys_device_id);\n+\t}\n+#endif /* FIRENZE_PCI_INVENTORY_DUMP */\n+}\n+\n+void firenze_pci_send_inventory(void)\n+{\n+\tuint64_t base, abase, end, aend, offset;\n+\tint64_t rc;\n+\n+\tif (!firenze_inv_data)\n+\t\treturn;\n+\n+\t/* Dump the inventory */\n+\tFIRENZE_PCI_INFO(\"Sending %d inventory to FSP\\n\",\n+\t\t\t firenze_inv_data->num_entries);\n+\tfirenze_dump_pci_inventory();\n+\n+\t/* Memory location for inventory */\n+ base = (uint64_t)firenze_inv_data;\n+ end = base +\n+\t sizeof(struct firenze_pci_inv_data) +\n+\t firenze_inv_data->num_entries * firenze_inv_data->entry_size;\n+\tabase = base & ~0xffful;\n+\taend = (end + 0xffful) & ~0xffful;\n+\toffset = PSI_DMA_PCIE_INVENTORY + (base & 0xfff);\n+\n+\t/* We can only accomodate so many entries in the PSI map */\n+\tif ((aend - abase) > PSI_DMA_PCIE_INVENTORY_SIZE) {\n+\t\tFIRENZE_PCI_ERR(\"Inventory (%lld bytes) too large\\n\",\n+\t\t\t\taend - abase);\n+\t\tgoto bail;\n+\t}\n+\n+\t/* Map this in the TCEs */\n+\tfsp_tce_map(PSI_DMA_PCIE_INVENTORY, (void *)abase, aend - abase);\n+\n+\t/* Send FSP message */\n+\trc = fsp_sync_msg(fsp_mkmsg(FSP_CMD_PCI_POWER_CONF, 3,\n+\t\t\t\t hi32(offset), lo32(offset),\n+\t\t\t\t end - base), true);\n+\tif (rc)\n+\t\tFIRENZE_PCI_ERR(\"Error %lld sending inventory\\n\",\n+\t\t\t\trc);\n+\n+\t/* Unmap */\n+\tfsp_tce_unmap(PSI_DMA_PCIE_INVENTORY, aend - abase);\n+bail:\n+\t/*\n+\t * We free the inventory. We'll have to redo that on hotplug\n+\t * when we support it but that isn't the case yet\n+\t */\n+\tfree(firenze_inv_data);\n+\tfirenze_inv_data = NULL;\n+\tfirenze_inv_cnt = 0;\n+}\n+\n+/* The function is called when the I2C request is completed\n+ * successfully, or with errors.\n+ */\n+static void firenze_i2c_req_done(int rc, struct i2c_request *req)\n+{\n+\tstruct pci_slot *slot = req->user_data;\n+\tuint32_t state;\n+\n+\t/* Check if there are errors for the completion */\n+\tif (rc) {\n+\t\tFIRENZE_PCI_ERR(\"Error %d from I2C request on slot %016llx\\n\",\n+\t\t\t\trc, slot->id);\n+\t\treturn;\n+\t}\n+\n+\t/* Check the request type */\n+\tif (req->op != SMBUS_READ && req->op != SMBUS_WRITE) {\n+\t\tFIRENZE_PCI_ERR(\"Invalid I2C request %d on slot %016llx\\n\",\n+\t\t\t\treq->op, slot->id);\n+\t\treturn;\n+\t}\n+\n+\t/* After writting power status to I2C slave, we need at least\n+\t * 5ms delay for the slave to settle down. We also have the\n+\t * delay after reading the power status as well.\n+\t */\n+\tswitch (slot->state) {\n+\tcase FIRENZE_PCI_SLOT_FRESET_WAIT_RSP:\n+\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: I2C request completed\\n\",\n+\t\t\t\tslot->id);\n+\t\tstate = FIRENZE_PCI_SLOT_FRESET_DELAY;\n+\t\tbreak;\n+\tcase FIRENZE_PCI_SLOT_SPOWER_START:\n+\t\tFIRENZE_PCI_DBG(\"%016llx SPOWER: I2C request completed\\n\",\n+\t\t\t\tslot->id);\n+\t\tstate = FIRENZE_PCI_SLOT_SPOWER_DONE;\n+\t\tbreak;\n+\tdefault:\n+\t\tFIRENZE_PCI_ERR(\"Wrong state %08x on slot %016llx\\n\",\n+\t\t\t\tslot->state, slot->id);\n+\t\treturn;\n+\t}\n+\n+\t/* Switch to net state */\n+\tpci_slot_set_state(slot, state);\n+}\n+\n+/* This function is called to setup normal PCI device or PHB slot.\n+ * For the later case, the slot doesn't have the associated PCI\n+ * device. Besides, the I2C response timeout is set to 5s. We might\n+ * improve I2C in future to support priorized requests so that the\n+ * timeout can be shortened.\n+ */\n+static int64_t firenze_pci_slot_freset(struct pci_slot *slot)\n+{\n+\tstruct firenze_pci_slot *plat_slot = slot->data;\n+\tuint8_t *pval, presence = 1;\n+\n+\tswitch (slot->state) {\n+\tcase FIRENZE_PCI_SLOT_NORMAL:\n+\tcase FIRENZE_PCI_SLOT_FRESET_START:\n+\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Starts\\n\",\n+\t\t\t\tslot->id);\n+\n+\t\t/* Bail if nothing is 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\tFIRENZE_PCI_DBG(\"%016llx FRESET: No device\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\treturn OPAL_SUCCESS;\n+\t\t}\n+\n+\t\t/* Prepare link down */\n+\t\tif (slot->ops.prepare_link_change) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Prepares link down\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\tslot->ops.prepare_link_change(slot, false);\n+\t\t}\n+\n+\t\t/* Send I2C request */\n+\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Check power state\\n\",\n+\t\t\t\tslot->id);\n+\t\tplat_slot->next_state =\n+\t\t\tFIRENZE_PCI_SLOT_FRESET_POWER_STATE;\n+\t\tplat_slot->req->op = SMBUS_READ;\n+\t\tslot->retries = FIRENZE_PCI_SLOT_RETRIES;\n+\t\tpci_slot_set_state(slot,\n+\t\t\tFIRENZE_PCI_SLOT_FRESET_WAIT_RSP);\n+\t\tif (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))\n+\t\t\ti2c_set_req_timeout(plat_slot->req,\n+\t\t\t\t\t FIRENZE_PCI_I2C_TIMEOUT);\n+\t\telse\n+\t\t\ti2c_set_req_timeout(plat_slot->req, 0ul);\n+\t\ti2c_queue_req(plat_slot->req);\n+\t\treturn pci_slot_set_sm_timeout(slot,\n+\t\t\t\tmsecs_to_tb(FIRENZE_PCI_SLOT_DELAY));\n+\tcase FIRENZE_PCI_SLOT_FRESET_WAIT_RSP:\n+\t\tif (slot->retries-- == 0) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Timeout waiting for %08x\\n\",\n+\t\t\t\t\tslot->id, plat_slot->next_state);\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tcheck_timers(false);\n+\t\treturn pci_slot_set_sm_timeout(slot,\n+\t\t\t\tmsecs_to_tb(FIRENZE_PCI_SLOT_DELAY));\n+\tcase FIRENZE_PCI_SLOT_FRESET_DELAY:\n+\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Delay %dms on I2C completion\\n\",\n+\t\t\t\tslot->id, FIRENZE_PCI_SLOT_DELAY);\n+\t\tpci_slot_set_state(slot, plat_slot->next_state);\n+\t\treturn pci_slot_set_sm_timeout(slot,\n+\t\t\t\tmsecs_to_tb(FIRENZE_PCI_SLOT_DELAY));\n+\tcase FIRENZE_PCI_SLOT_FRESET_POWER_STATE:\n+\t\t/* Update last power status */\n+\t\tpval = (uint8_t *)(plat_slot->req->rw_buf);\n+\t\t*plat_slot->power_status = *pval;\n+\n+\t\t/* Power is on, turn it off */\n+\t\tif (((*pval) & plat_slot->power_mask) == plat_slot->power_on) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Power (%02x) on, turn off\\n\",\n+\t\t\t\t\tslot->id, *pval);\n+\t\t\t(*pval) &= ~plat_slot->power_mask;\n+\t\t\t(*pval) |= plat_slot->power_off;\n+\t\t\tplat_slot->req->op = SMBUS_WRITE;\n+\t\t\tslot->retries = FIRENZE_PCI_SLOT_RETRIES;\n+\t\t\tplat_slot->next_state =\n+\t\t\t\tFIRENZE_PCI_SLOT_FRESET_POWER_OFF;\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tFIRENZE_PCI_SLOT_FRESET_WAIT_RSP);\n+\n+\t\t\tif (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))\n+\t\t\t\ti2c_set_req_timeout(plat_slot->req,\n+\t\t\t\t\t\t FIRENZE_PCI_I2C_TIMEOUT);\n+\t\t\telse\n+\t\t\t\ti2c_set_req_timeout(plat_slot->req, 0ul);\n+\t\t\ti2c_queue_req(plat_slot->req);\n+\t\t\treturn pci_slot_set_sm_timeout(slot,\n+\t\t\t\t\tmsecs_to_tb(FIRENZE_PCI_SLOT_DELAY));\n+\t\t}\n+\n+\t\t/* Fall through: Power is off, turn it on */\n+\tcase FIRENZE_PCI_SLOT_FRESET_POWER_OFF:\n+\t\t/* Update last power status */\n+\t\tpval = (uint8_t *)(plat_slot->req->rw_buf);\n+\t\t*plat_slot->power_status = *pval;\n+\n+\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Power (%02x) off, turn on\\n\",\n+\t\t\t\tslot->id, *pval);\n+\t\t(*pval) &= ~plat_slot->power_mask;\n+\t\t(*pval) |= plat_slot->power_on;\n+\t\tplat_slot->req->op = SMBUS_WRITE;\n+\t\tplat_slot->next_state =\n+\t\t\tFIRENZE_PCI_SLOT_FRESET_POWER_ON;\n+\t\tslot->retries = FIRENZE_PCI_SLOT_RETRIES;\n+\t\tpci_slot_set_state(slot,\n+\t\t\tFIRENZE_PCI_SLOT_FRESET_WAIT_RSP);\n+\n+\t\tif (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))\n+\t\t\ti2c_set_req_timeout(plat_slot->req,\n+\t\t\t\t\t FIRENZE_PCI_I2C_TIMEOUT);\n+\t\telse\n+\t\t\ti2c_set_req_timeout(plat_slot->req, 0ul);\n+\t\ti2c_queue_req(plat_slot->req);\n+\t\treturn pci_slot_set_sm_timeout(slot,\n+\t\t\t\tmsecs_to_tb(FIRENZE_PCI_SLOT_DELAY));\n+\tcase FIRENZE_PCI_SLOT_FRESET_POWER_ON:\n+\t\t/* Update last power status */\n+\t\tpval = (uint8_t *)(plat_slot->req->rw_buf);\n+\t\t*plat_slot->power_status = *pval;\n+\n+\t\t/* PHB3 slot supports post fundamental reset, we switch\n+\t\t * to that. For normal PCI slot, we switch to hot reset\n+\t\t * instead.\n+\t\t */\n+\t\tif (slot->ops.pfreset) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Switch to PFRESET\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tFIRENZE_PCI_SLOT_PFRESET_START);\n+\t\t\treturn slot->ops.pfreset(slot);\n+\t\t} else if (slot->ops.hreset) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Switch to HRESET\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tFIRENZE_PCI_SLOT_HRESET_START);\n+\t\t\treturn slot->ops.hreset(slot);\n+\t\t}\n+\n+\t\tpci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);\n+\t\treturn OPAL_SUCCESS;\n+\tdefault:\n+\t\tFIRENZE_PCI_DBG(\"%016llx FRESET: Unexpected state %08x\\n\",\n+\t\t\t\tslot->id, slot->state);\n+\t}\n+\n+out:\n+\tpci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);\n+\treturn OPAL_HARDWARE;\n+}\n+\n+static int64_t firenze_pci_slot_perst(struct pci_slot *slot)\n+{\n+\tstruct firenze_pci_slot *plat_slot = slot->data;\n+\tuint8_t presence = 1;\n+\tuint16_t ctrl;\n+\n+\tswitch (slot->state) {\n+\tcase FIRENZE_PCI_SLOT_NORMAL:\n+\tcase FIRENZE_PCI_SLOT_FRESET_START:\n+\t\tFIRENZE_PCI_DBG(\"%016llx PERST: Starts\\n\",\n+\t\t\t\tslot->id);\n+\n+\t\t/* Bail if nothing is 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\tFIRENZE_PCI_DBG(\"%016llx PERST: No device\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\treturn OPAL_SUCCESS;\n+\t\t}\n+\n+\t\t/* Prepare link down */\n+\t\tif (slot->ops.prepare_link_change) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx PERST: Prepare link down\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\tslot->ops.prepare_link_change(slot, false);\n+\t\t}\n+\n+\t\t/* Assert PERST */\n+\t\tFIRENZE_PCI_DBG(\"%016llx PERST: Assert\\n\",\n+\t\t\t\tslot->id);\n+\t\tpci_cfg_read16(slot->phb, slot->pd->bdfn,\n+\t\t\t plat_slot->perst_reg, &ctrl);\n+\t\tctrl |= plat_slot->perst_bit;\n+\t\tpci_cfg_write16(slot->phb, slot->pd->bdfn,\n+\t\t\t\tplat_slot->perst_reg, ctrl);\n+\t\tpci_slot_set_state(slot,\n+\t\t\tFIRENZE_PCI_SLOT_PERST_DEASSERT);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(250));\n+\tcase FIRENZE_PCI_SLOT_PERST_DEASSERT:\n+\t\t/* Deassert PERST */\n+\t\tpci_cfg_read16(slot->phb, slot->pd->bdfn,\n+\t\t\t plat_slot->perst_reg, &ctrl);\n+\t\tctrl &= ~plat_slot->perst_bit;\n+\t\tpci_cfg_write16(slot->phb, slot->pd->bdfn,\n+\t\t\t\tplat_slot->perst_reg, ctrl);\n+\t\tpci_slot_set_state(slot,\n+\t\t\tFIRENZE_PCI_SLOT_PERST_DELAY);\n+\t\treturn pci_slot_set_sm_timeout(slot, msecs_to_tb(1500));\n+\tcase FIRENZE_PCI_SLOT_PERST_DELAY:\n+\t\t/*\n+\t\t * Switch to post fundamental reset if the slot supports\n+\t\t * that. Otherwise, we issue a proceeding hot reset on\n+\t\t * the slot.\n+\t\t */\n+\t\tif (slot->ops.pfreset) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx PERST: Switch to PFRESET\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tFIRENZE_PCI_SLOT_PFRESET_START);\n+\t\t\treturn slot->ops.pfreset(slot);\n+\t\t} else if (slot->ops.hreset) {\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx PERST: Switch to HRESET\\n\",\n+\t\t\t\t\tslot->id);\n+\t\t\tpci_slot_set_state(slot,\n+\t\t\t\tFIRENZE_PCI_SLOT_HRESET_START);\n+\t\t\treturn slot->ops.hreset(slot);\n+\t\t}\n+\n+\t\tpci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);\n+\t\treturn OPAL_SUCCESS;\n+\tdefault:\n+\t\tFIRENZE_PCI_DBG(\"%016llx PERST: Unexpected state %08x\\n\",\n+\t\t\t\tslot->id, slot->state);\n+\t}\n+\n+\tpci_slot_set_state(slot, FIRENZE_PCI_SLOT_NORMAL);\n+\treturn OPAL_HARDWARE;\n+}\n+\n+static int64_t firenze_pci_slot_get_power_state(struct pci_slot *slot,\n+\t\t\t\t\t\tuint8_t *val)\n+{\n+\tif (slot->state != FIRENZE_PCI_SLOT_NORMAL)\n+\t\tFIRENZE_PCI_ERR(\"%016llx GPOWER: Unexpected state %08x\\n\",\n+\t\t\t\tslot->id, slot->state);\n+\n+\t*val = slot->power_state;\n+\treturn OPAL_SUCCESS;\n+}\n+\n+static int64_t firenze_pci_slot_set_power_state(struct pci_slot *slot,\n+\t\t\t\t\t\tuint8_t val)\n+{\n+\tstruct firenze_pci_slot *plat_slot = slot->data;\n+\tuint8_t *pval;\n+\n+\tif (slot->state != FIRENZE_PCI_SLOT_NORMAL)\n+\t\tFIRENZE_PCI_ERR(\"%016llx SPOWER: Unexpected state %08x\\n\",\n+\t\t\t\tslot->id, slot->state);\n+\n+\tif (val != PCI_SLOT_POWER_OFF && val != PCI_SLOT_POWER_ON)\n+\t\treturn OPAL_PARAMETER;\n+\n+\tif (slot->power_state == val)\n+\t\treturn OPAL_SUCCESS;\n+\n+\tslot->power_state = val;\n+\tpci_slot_set_state(slot, FIRENZE_PCI_SLOT_SPOWER_START);\n+\n+\tplat_slot->req->op = SMBUS_WRITE;\n+\tpval = (uint8_t *)plat_slot->req->rw_buf;\n+\tif (val == PCI_SLOT_POWER_ON) {\n+\t\t*pval = *plat_slot->power_status;\n+\t\t(*pval) &= ~plat_slot->power_mask;\n+\t\t(*pval) |= plat_slot->power_on;\n+\t} else {\n+\t\t*pval = *plat_slot->power_status;\n+\t\t(*pval) &= ~plat_slot->power_mask;\n+\t\t(*pval) |= plat_slot->power_off;\n+\t}\n+\n+\tif (pci_slot_has_flags(slot, PCI_SLOT_FLAG_BOOTUP))\n+\t\ti2c_set_req_timeout(plat_slot->req, FIRENZE_PCI_I2C_TIMEOUT);\n+\telse\n+\t\ti2c_set_req_timeout(plat_slot->req, 0ul);\n+\ti2c_queue_req(plat_slot->req);\n+\n+\treturn OPAL_ASYNC_COMPLETION;\n+}\n+\n+static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip,\n+\t\t\t\t\t\tuint8_t eng,\n+\t\t\t\t\t\tuint8_t port)\n+{\n+\tstruct dt_node *np, *child;\n+\tuint32_t reg;\n+\n+\t/* Iterate I2C masters */\n+\tdt_for_each_compatible(dt_root, np, \"ibm,power8-i2cm\") {\n+\t\tif (!np->parent ||\n+\t\t !dt_node_is_compatible(np->parent, \"ibm,power8-xscom\"))\n+\t\t\tcontinue;\n+\n+\t\t/* Check chip index */\n+\t\treg = dt_prop_get_u32(np->parent, \"ibm,chip-id\");\n+\t\tif (reg != chip)\n+\t\t\tcontinue;\n+\n+\t\t/* Check I2C master index */\n+\t\treg = dt_prop_get_u32(np, \"chip-engine#\");\n+\t\tif (reg != eng)\n+\t\t\tcontinue;\n+\n+\t\t/* Iterate I2C buses */\n+\t\tdt_for_each_child(np, child) {\n+\t\t\tif (!dt_node_is_compatible(child, \"ibm,power8-i2c-port\"))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/* Check I2C port index */\n+\t\t\treg = dt_prop_get_u32(child, \"reg\");\n+\t\t\tif (reg != port)\n+\t\t\t\tcontinue;\n+\n+\t\t\treg = dt_prop_get_u32(child, \"ibm,opal-id\");\n+\t\t\treturn i2c_find_bus_by_id(reg);\n+\t\t}\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static void firenze_pci_slot_init(struct pci_slot *slot)\n+{\n+\tstruct lxvpd_pci_slot *s = slot->data;\n+\tstruct firenze_pci_slot *plat_slot = slot->data;\n+\tstruct firenze_pci_slot_info *info = NULL;\n+\tuint32_t vdid;\n+\tuint8_t buddy;\n+\tint i;\n+\n+\t/* Search for PCI slot info */\n+\tfor (i = 0; i < ARRAY_SIZE(firenze_pci_slots); i++) {\n+\t\tif (firenze_pci_slots[i].index == s->slot_index &&\n+\t\t !strcmp(firenze_pci_slots[i].label, s->label)) {\n+\t\t\tinfo = &firenze_pci_slots[i];\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (!info)\n+\t\treturn;\n+\n+\t/* Search I2C bus for external power mgt */\n+\tbuddy = info->buddy;\n+\tplat_slot->i2c_bus = firenze_pci_find_i2c_bus(info->chip_id,\n+\t\t\t\t\t\t info->master_id,\n+\t\t\t\t\t\t info->port_id);\n+\tif (plat_slot->i2c_bus) {\n+\t\tplat_slot->req = i2c_alloc_req(plat_slot->i2c_bus);\n+\t\tif (!plat_slot->req)\n+\t\t\tplat_slot->i2c_bus = NULL;\n+\n+\t\tplat_slot->req->dev_addr\t= info->slave_addr;\n+\t\tplat_slot->req->offset_bytes\t= 1;\n+\t\tplat_slot->req->offset\t\t= 0x69;\n+\t\tplat_slot->req->rw_buf\t\t= plat_slot->i2c_rw_buf;\n+\t\tplat_slot->req->rw_len\t\t= 1;\n+\t\tplat_slot->req->completion\t= firenze_i2c_req_done;\n+\t\tplat_slot->req->user_data\t= slot;\n+\t\tswitch (info->channel) {\n+\t\tcase 0:\n+\t\t\tplat_slot->power_status = &firenze_pci_slots[buddy].power_status;\n+\t\t\tplat_slot->power_mask = 0x33;\n+\t\t\tplat_slot->power_on = 0x22;\n+\t\t\tplat_slot->power_off = 0x33;\n+\t\t\tbreak;\n+\t\tcase 1:\n+\t\t\tplat_slot->power_status = &firenze_pci_slots[buddy].power_status;\n+\t\t\tplat_slot->power_mask = 0xcc;\n+\t\t\tplat_slot->power_on = 0x88;\n+\t\t\tplat_slot->power_off = 0xcc;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tFIRENZE_PCI_DBG(\"%016llx: Invalid channel %d\\n\",\n+\t\t\t\t\tslot->id, info->channel);\n+\t\t\tplat_slot->i2c_bus = NULL;\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * If the slot has external power logic, to override the\n+\t * default power management methods. Because of the bad\n+\t * I2C design, the API supplied by I2C is really hard to\n+\t * be utilized. To figure out power status retrival or\n+\t * configuration after we have a blocking API for that.\n+\t */\n+\tif (plat_slot->i2c_bus) {\n+\t\tslot->ops.freset = firenze_pci_slot_freset;\n+\t\tslot->ops.get_power_state = firenze_pci_slot_get_power_state;\n+\t\tslot->ops.set_power_state = firenze_pci_slot_set_power_state;\n+\t\tFIRENZE_PCI_DBG(\"%016llx: External power mgt initialized\\n\",\n+\t\t\t\tslot->id);\n+\t} else if (info->inband_perst) {\n+\t\t/*\n+\t\t * For PLX downstream ports, PCI config register can be\n+\t\t * leveraged to do PERST. If the slot doesn't have external\n+\t\t * power management stuff, lets try to stick to the PERST\n+\t\t * logic if applicable\n+\t\t */\n+\t\tif (slot->pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) {\n+\t\t\tpci_cfg_read32(slot->phb, slot->pd->bdfn,\n+\t\t\t\t PCI_CFG_VENDOR_ID, &vdid);\n+\t\t\tswitch (vdid) {\n+\t\t\tcase 0x873210b5: /* PLX8732 */\n+\t\t\tcase 0x874810b5: /* PLX8748 */\n+\t\t\t\tplat_slot->perst_reg = 0x80;\n+\t\t\t\tplat_slot->perst_bit = 0x0400;\n+\t\t\t\tslot->ops.freset = firenze_pci_slot_perst;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/*\n+ * Anyway, the slot has platform specific info. That\n+ * requires platform specific method to parse it out\n+ * properly.\n+ */\n+\tslot->ops.add_properties = lxvpd_add_slot_properties;\n+}\n+\n+void firenze_pci_setup_phb(struct phb *phb, unsigned int index)\n+{\n+\tuint32_t hub_id;\n+\tstruct pci_slot *slot;\n+\tstruct lxvpd_pci_slot *s;\n+\n+\t/* Grab Hub ID used to parse VPDs */\n+\thub_id = dt_prop_get_u32_def(phb->dt_node, \"ibm,hub-id\", 0);\n+\n+\t/* Process the pcie slot entries from the lx vpd lid */\n+\tlxvpd_process_slot_entries(phb, dt_root, hub_id,\n+\t\t\t\t index, sizeof(struct firenze_pci_slot));\n+\n+\t/* Fixup PHB3 slot */\n+\tslot = phb->slot;\n+\ts = slot ? lxvpd_get_slot(slot) : NULL;\n+\tif (s) {\n+ lxvpd_extract_info(slot, s);\n+\t\tfirenze_pci_slot_init(slot);\n+\t}\n+}\n+\n+static void firenze_pci_i2c_complete(int rc, struct i2c_request *req)\n+{\n+\t*(int *)req->user_data = rc;\n+}\n+\n+static void firenze_pci_do_i2c_byte(uint8_t chip, uint8_t eng, uint8_t port,\n+\t\t\t\t uint8_t addr, uint8_t reg, uint8_t data)\n+{\n+\tstruct i2c_bus *bus;\n+\tstruct i2c_request *req;\n+\tuint8_t verif;\n+\tint rc;\n+\n+ bus = firenze_pci_find_i2c_bus(chip, eng, port);\n+ if (!bus) {\n+ prerror(\"FIRENZE: Failed to find i2c (%d/%d/%d)\\n\", chip, eng, port);\n+ return;\n+ }\n+ req = i2c_alloc_req(bus);\n+ if (!req) {\n+ prerror(\"FIRENZE: Failed to allocate i2c request\\n\");\n+ return;\n+ }\n+ req->op = SMBUS_WRITE;\n+ req->dev_addr = addr >> 1;\n+ req->offset_bytes = 1;\n+ req->offset = reg;\n+ req->rw_buf = &data;\n+ req->rw_len = 1;\n+ req->completion = firenze_pci_i2c_complete;\n+ req->user_data = &rc;\n+ rc = 1;\n+ i2c_queue_req(req);\n+ while(rc == 1) {\n+ time_wait_us(10);\n+ }\n+ if (rc != 0) {\n+ prerror(\"FIRENZE: I2C error %d writing byte\\n\", rc);\n+ return;\n+ }\n+ req->op = SMBUS_READ;\n+ req->dev_addr = addr >> 1;\n+ req->offset_bytes = 1;\n+ req->offset = reg;\n+ req->rw_buf = &verif;\n+ req->rw_len = 1;\n+ req->completion = firenze_pci_i2c_complete;\n+ req->user_data = &rc;\n+ rc = 1;\n+ i2c_queue_req(req);\n+ while(rc == 1) {\n+ time_wait_us(10);\n+ }\n+ if (rc != 0) {\n+ prerror(\"FIRENZE: I2C error %d reading byte\\n\", rc);\n+ return;\n+ }\n+ if (verif != data) {\n+ prerror(\"FIRENZE: I2C miscompare want %02x got %02x\\n\", data, verif);\n+ }\n+}\n+\n+static void firenze_pci_slot_fixup(struct pci_slot *slot)\n+{\n+\tuint64_t id;\n+\tconst uint32_t *p;\n+\tstruct lxvpd_pci_slot *s;\n+\n+\tp = dt_prop_get_def(dt_root, \"ibm,vpd-lx-info\", NULL);\n+\tif (!p)\n+\t\treturn;\n+\n+\t/* FIXME: support fixup with generic way */\n+\tid = ((uint64_t)p[1] << 32) | p[2];\n+\tid = 0;\n+\tif (id != LX_VPD_2S4U_BACKPLANE &&\n+\t id != LX_VPD_1S4U_BACKPLANE)\n+\t\treturn;\n+\n+\ts = slot->data;\n+\tif (!s || !s->pluggable)\n+\t\treturn;\n+\n+\t/* Note: We apply the settings twice for C6/C7 but that shouldn't\n+\t * be a problem\n+\t */\n+\tif (!strncmp(s->label, \"C6 \", 2) ||\n+\t !strncmp(s->label, \"C7 \", 2)) {\n+\t\tprintf(\"FIRENZE: Fixing power on %s...\\n\", s->label);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5e, 0xfa);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5a, 0xff);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x6a, 0x5b, 0xff);\n+\t} else if (!strncmp(s->label, \"C5 \", 2)) {\n+ printf(\"FIRENZE: Fixing power on %s...\\n\", s->label);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x72, 0x5e, 0xfb);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x72, 0x5b, 0xff);\n+ } else if (!strncmp(s->label, \"C3 \", 2)) {\n+\t\tprintf(\"FIRENZE: Fixing power on %s...\\n\", s->label);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x74, 0x5e, 0xfb);\n+\t\tfirenze_pci_do_i2c_byte(0, 1, 0, 0x74, 0x5b, 0xff);\n+ }\n+}\n+\n+void firenze_pci_get_slot_info(struct phb *phb, struct pci_device *pd)\n+{\n+\tstruct pci_slot *slot;\n+\tstruct lxvpd_pci_slot *s;\n+\n+\t/* Prepare the PCI inventory */\n+\tfirenze_pci_add_inventory(phb, pd);\n+\n+\tif (pd->dev_type != PCIE_TYPE_ROOT_PORT &&\n+\t pd->dev_type != PCIE_TYPE_SWITCH_UPPORT &&\n+\t pd->dev_type != PCIE_TYPE_SWITCH_DNPORT &&\n+\t pd->dev_type != PCIE_TYPE_PCIE_TO_PCIX)\n+\t\treturn;\n+\n+\t/* Create PCIe slot */\n+\tslot = pcie_slot_create(phb, pd);\n+\tif (!slot)\n+\t\treturn;\n+\n+\t/* Root complex inherits methods from PHB slot */\n+\tif (!pd->parent && phb->slot)\n+\t\tmemcpy(&slot->ops, &phb->slot->ops, sizeof(struct pci_slot_ops));\n+\n+\t/* Patch PCIe slot */\n+\ts = lxvpd_get_slot(slot);\n+\tif (s) {\n+\t\tlxvpd_extract_info(slot, s);\n+\t\tfirenze_pci_slot_init(slot);\n+\t}\n+\n+\t/* Fixup the slot's power status */\n+\tfirenze_pci_slot_fixup(slot);\n+}\ndiff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c\nindex 75f566c..00aba8d 100644\n--- a/platforms/ibm-fsp/firenze.c\n+++ b/platforms/ibm-fsp/firenze.c\n@@ -28,30 +28,6 @@\n #include \"ibm-fsp.h\"\n #include \"lxvpd.h\"\n \n-/* Structure used to send PCIe card info to FSP */\n-struct fsp_pcie_entry {\n-\tuint32_t\thw_proc_id;\n-\tuint16_t\tslot_idx;\n-\tuint16_t\treserved;\n-\tuint16_t\tvendor_id;\n-\tuint16_t\tdevice_id;\n-\tuint16_t\tsubsys_vendor_id;\n-\tuint16_t\tsubsys_device_id;\n-};\n-\n-struct fsp_pcie_inventory {\n-\tuint32_t\t\tversion; /* currently 1 */\n-\tuint32_t\t\tnum_entries;\n-\tuint32_t\t\tentry_size;\n-\tuint32_t\t\tentry_offset;\n-\tstruct fsp_pcie_entry\tentries[];\n-};\n-\n-static struct fsp_pcie_inventory *fsp_pcie_inv;\n-static unsigned int fsp_pcie_inv_alloc_count;\n-#define FSP_PCIE_INV_ALLOC_CHUNK\t4\n-static uint64_t lx_vpd_id;\n-\n struct lock fsp_pcie_inv_lock = LOCK_UNLOCKED;\n \n static struct dt_node *dt_create_i2c_master(struct dt_node *n, uint32_t eng_id)\n@@ -122,44 +98,6 @@ static struct dt_node *dt_create_i2c_device(struct dt_node *bus, uint8_t addr,\n \treturn dev;\n }\n \n-static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip, uint8_t eng, uint8_t port)\n-{\n- struct dt_node *np, *child;\n- uint32_t reg;\n-\n- /* Iterate I2C masters */\n- dt_for_each_compatible(dt_root, np, \"ibm,power8-i2cm\") {\n- if (!np->parent ||\n- !dt_node_is_compatible(np->parent, \"ibm,power8-xscom\"))\n- continue;\n-\n- /* Check chip index */\n- reg = dt_prop_get_u32(np->parent, \"ibm,chip-id\");\n- if (reg != chip)\n- continue;\n-\n- /* Check I2C master index */\n- reg = dt_prop_get_u32(np, \"chip-engine#\");\n- if (reg != eng)\n- continue;\n-\n- /* Iterate I2C buses */\n- dt_for_each_child(np, child) {\n- if (!dt_node_is_compatible(child, \"ibm,power8-i2c-port\"))\n- continue;\n-\n- /* Check I2C port index */\n- reg = dt_prop_get_u32(child, \"reg\");\n- if (reg != port)\n- continue;\n-\n- reg = dt_prop_get_u32(child, \"ibm,opal-id\");\n- return i2c_find_bus_by_id(reg);\n- }\n- }\n- return NULL;\n-}\n-\n static void firenze_dt_fixup_i2cm(void)\n {\n \tstruct dt_node *master, *bus, *dev;\n@@ -256,281 +194,6 @@ static bool firenze_probe(void)\n \treturn true;\n }\n \n-static void firenze_send_pci_inventory(void)\n-{\n-\tuint64_t base, abase, end, aend, offset;\n-\tint64_t rc;\n-\n-\tif (!fsp_pcie_inv)\n-\t\treturn;\n-\n-\tprlog(PR_DEBUG, \"PLAT: Sending PCI inventory to FSP, table has\"\n-\t \" %d entries\\n\",\n-\t fsp_pcie_inv->num_entries);\n-\n-\t{\n-\t\tunsigned int i;\n-\n-\t\tprlog(PR_DEBUG, \"HWP SLT VDID DVID SVID SDID\\n\");\n-\t\tprlog(PR_DEBUG, \"---------------------------\\n\");\n-\t\tfor (i = 0; i < fsp_pcie_inv->num_entries; i++) {\n-\t\t\tstruct fsp_pcie_entry *e = &fsp_pcie_inv->entries[i];\n-\n-\t\t\tprlog(PR_DEBUG, \"%03d %03d %04x %04x %04x %04x\\n\",\n-\t\t\t e->hw_proc_id, e->slot_idx,\n-\t\t\t e->vendor_id, e->device_id,\n-\t\t\t e->subsys_vendor_id, e->subsys_device_id);\n-\t\t}\n-\t}\n-\n-\t/*\n-\t * Get the location of the table in a form we can send\n-\t * to the FSP\n-\t */\n-\tbase = (uint64_t)fsp_pcie_inv;\n-\tend = base + sizeof(struct fsp_pcie_inventory) +\n-\t\tfsp_pcie_inv->num_entries * fsp_pcie_inv->entry_size;\n-\tabase = base & ~0xffful;\n-\taend = (end + 0xffful) & ~0xffful;\n-\toffset = PSI_DMA_PCIE_INVENTORY + (base & 0xfff);\n-\n-\t/* We can only accommodate so many entries in the PSI map */\n-\tif ((aend - abase) > PSI_DMA_PCIE_INVENTORY_SIZE) {\n-\t\tprerror(\"PLAT: PCIe inventory too large (%lld bytes)\\n\",\n-\t\t\taend - abase);\n-\t\tgoto bail;\n-\t}\n-\n-\t/* Map this in the TCEs */\n-\tfsp_tce_map(PSI_DMA_PCIE_INVENTORY, (void *)abase, aend - abase);\n-\n-\t/* Send FSP message */\n-\trc = fsp_sync_msg(fsp_mkmsg(FSP_CMD_PCI_POWER_CONF, 3,\n-\t\t\t\t hi32(offset), lo32(offset),\n-\t\t\t\t end - base), true);\n-\tif (rc)\n-\t\tprerror(\"PLAT: FSP error %lld sending inventory\\n\", rc);\n-\n-\t/* Unmap */\n-\tfsp_tce_unmap(PSI_DMA_PCIE_INVENTORY, aend - abase);\n- bail:\n-\t/*\n-\t * We free the inventory. We'll have to redo that on hotplug\n-\t * when we support it but that isn't the case yet\n-\t */\n-\tfree(fsp_pcie_inv);\n-\tfsp_pcie_inv = NULL;\n-}\n-\n-static void firenze_i2c_complete(int rc, struct i2c_request *req)\n-{\n-\t*(int *)req->user_data = rc;\n-}\n-\n-static void firenze_do_i2c_byte(uint8_t chip, uint8_t eng, uint8_t port,\n-\t\t\t\tuint8_t addr, uint8_t reg, uint8_t data)\n-{\n-\tstruct i2c_bus *bus;\n-\tstruct i2c_request *req;\n-\tuint8_t verif;\n-\tint rc;\n-\n-\tbus = firenze_pci_find_i2c_bus(chip, eng, port);\n-\tif (!bus) {\n-\t\tprerror(\"FIRENZE: Failed to find i2c (%d/%d/%d)\\n\", chip, eng, port);\n-\t\treturn;\n-\t}\n-\treq = i2c_alloc_req(bus);\n-\tif (!req) {\n-\t\tprerror(\"FIRENZE: Failed to allocate i2c request\\n\");\n-\t\treturn;\n-\t}\n-\treq->op\t\t = SMBUS_WRITE;\n-\treq->dev_addr = addr >> 1;\n-\treq->offset_bytes = 1;\n-\treq->offset = reg;\n-\treq->rw_buf = &data;\n-\treq->rw_len = 1;\n-\treq->completion = firenze_i2c_complete;\n-\treq->user_data\t = &rc;\n-\trc = 1;\n-\ti2c_queue_req(req);\n-\twhile(rc == 1) {\n-\t\ttime_wait_us(10);\n-\t}\n-\tif (rc != 0) {\n-\t\tprerror(\"FIRENZE: I2C error %d writing byte\\n\", rc);\n-\t\treturn;\n-\t}\n-\treq->op\t\t = SMBUS_READ;\n-\treq->dev_addr = addr >> 1;\n-\treq->offset_bytes = 1;\n-\treq->offset = reg;\n-\treq->rw_buf = &verif;\n-\treq->rw_len = 1;\n-\treq->completion = firenze_i2c_complete;\n-\treq->user_data\t = &rc;\n-\trc = 1;\n-\ti2c_queue_req(req);\n-\twhile(rc == 1) {\n-\t\ttime_wait_us(10);\n-\t}\n-\tif (rc != 0) {\n-\t\tprerror(\"FIRENZE: I2C error %d reading byte\\n\", rc);\n-\t\treturn;\n-\t}\n-\tif (verif != data) {\n-\t\tprerror(\"FIRENZE: I2C miscompare want %02x got %02x\\n\", data, verif);\n-\t}\n-}\n-\n-static void firenze_fixup_pcie_slot_power(struct pci_device * pd)\n-{\n-\tconst char *label = pd->slot_info->label;\n-\n-\tif (!pd->slot_info->pluggable)\n-\t\treturn;\n-\n-\tif (lx_vpd_id != LX_VPD_2S4U_BACKPLANE &&\n-\t lx_vpd_id != LX_VPD_1S4U_BACKPLANE)\n-\t\treturn;\n-\n-\tprintf(\"FIRENZE: Checking slot %s for power fixup\\n\", label);\n-\n-\t/* Note: We apply the settings twice for C6/C7 but that shouldn't\n-\t * be a problem\n-\t */\n-\tif (!strncmp(label, \"C6 \", 3) || !strncmp(label, \"C7 \", 3)) {\n-\t\tprintf(\"FIRENZE: Fixing power on %s...\\n\", label);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5e, 0xfa);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5a, 0xff);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5b, 0xff);\n-\t}\n-\tif (!strncmp(label, \"C5 \", 3)) {\n-\t\tprintf(\"FIRENZE: Fixing power on %s...\\n\", label);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x72, 0x5e, 0xfb);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x72, 0x5b, 0xff);\n-\t}\n-\tif (!strncmp(label, \"C3 \", 3)) {\n-\t\tprintf(\"FIRENZE: Fixing power on %s...\\n\", label);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x74, 0x5e, 0xfb);\n-\t\tfirenze_do_i2c_byte(0, 1, 0, 0x74, 0x5b, 0xff);\n-\t}\n-}\n-\n-static void firenze_add_pcidev_to_fsp_inventory(struct phb *phb,\n-\t\t\t\t\t\tstruct pci_device *pd)\n-{\n-\tstruct fsp_pcie_entry *entry;\n-\tstruct proc_chip *chip;\n-\n-\t/* Check if we need to do some (Re)allocation */\n-\tif (!fsp_pcie_inv ||\n-\t fsp_pcie_inv->num_entries == fsp_pcie_inv_alloc_count) {\n-\t\tunsigned int new_count;\n-\t\tsize_t new_size;\n-\t\tbool need_init = !fsp_pcie_inv;\n-\n-\t\t/* (Re)allocate the block to the new size */\n-\t\tnew_count = fsp_pcie_inv_alloc_count + FSP_PCIE_INV_ALLOC_CHUNK;\n-\t\tnew_size = sizeof(struct fsp_pcie_inventory);\n-\t\tnew_size += sizeof(struct fsp_pcie_entry) * new_count;\n-\t\tfsp_pcie_inv = realloc(fsp_pcie_inv, new_size);\n-\t\tfsp_pcie_inv_alloc_count = new_count;\n-\n-\t\t/* Initialize the header for a new inventory */\n-\t\tif (need_init) {\n-\t\t\tfsp_pcie_inv->version = 1;\n-\t\t\tfsp_pcie_inv->num_entries = 0;\n-\t\t\tfsp_pcie_inv->entry_size =\n-\t\t\t\tsizeof(struct fsp_pcie_entry);\n-\t\t\tfsp_pcie_inv->entry_offset =\n-\t\t\t\toffsetof(struct fsp_pcie_inventory, entries);\n-\t\t}\n-\t}\n-\n-\t/* Add entry */\n-\tentry = &fsp_pcie_inv->entries[fsp_pcie_inv->num_entries++];\n-\tchip = get_chip(dt_get_chip_id(phb->dt_node));\n-\tif (!chip) {\n-\t\tprerror(\"PLAT: Failed to get chip for PHB !\\n\");\n-\t\treturn;\n-\t}\n-\tentry->hw_proc_id = chip->pcid;\n-\tentry->slot_idx = pd->parent->slot_info->slot_index;\n-\tentry->reserved = 0;\n-\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_VENDOR_ID, &entry->vendor_id);\n-\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_DEVICE_ID, &entry->device_id);\n-\tif (pd->is_bridge) {\n-\t\tint64_t ssvc = pci_find_cap(phb, pd->bdfn,\n-\t\t\t\t\t PCI_CFG_CAP_ID_SUBSYS_VID);\n-\t\tif (ssvc < 0) {\n-\t\t\tentry->subsys_vendor_id = 0xffff;\n-\t\t\tentry->subsys_device_id = 0xffff;\n-\t\t} else {\n-\t\t\tpci_cfg_read16(phb, pd->bdfn,\n-\t\t\t\t ssvc + PCICAP_SUBSYS_VID_VENDOR,\n-\t\t\t\t &entry->subsys_vendor_id);\n-\t\t\tpci_cfg_read16(phb, pd->bdfn,\n-\t\t\t\t ssvc + PCICAP_SUBSYS_VID_DEVICE,\n-\t\t\t\t &entry->subsys_device_id);\n-\t\t}\n-\t} else {\n-\t\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_VENDOR_ID,\n-\t\t\t &entry->subsys_vendor_id);\n-\t\tpci_cfg_read16(phb, pd->bdfn, PCI_CFG_SUBSYS_ID,\n-\t\t\t &entry->subsys_device_id);\n-\t}\n-}\n-\n-static void firenze_get_slot_info(struct phb *phb, struct pci_device * pd)\n-{\n-\t/* Call the main LXVPD function first */\n-\tlxvpd_get_slot_info(phb, pd);\n-\n-\t/*\n-\t * Do we need to add that to the FSP inventory for power management ?\n-\t *\n-\t * For now, we only add devices that:\n-\t *\n-\t * - Are function 0\n-\t * - Are not an RC or a downstream bridge\n-\t * - Have a direct parent that has a slot entry\n-\t * - Slot entry says pluggable\n-\t * - Aren't an upstream switch that has slot info\n-\t */\n-\tif (!pd)\n-\t\treturn;\n-\tif (pd->dev_type == PCIE_TYPE_ROOT_PORT ||\n-\t pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) {\n-\t\tfirenze_fixup_pcie_slot_power(pd);\n-\t\treturn;\n-\t}\n-\tif (pd->bdfn & 7)\n-\t\treturn;\n-\tif (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT &&\n-\t pd->slot_info)\n-\t\treturn;\n-\tif (!pd->parent || !pd->parent->slot_info)\n-\t\treturn;\n-\tif (!pd->parent->slot_info->pluggable)\n-\t\treturn;\n-\tlock(&fsp_pcie_inv_lock);\n-\tfirenze_add_pcidev_to_fsp_inventory(phb, pd);\n-\tunlock(&fsp_pcie_inv_lock);\n-}\n-\n-static void firenze_setup_phb(struct phb *phb, unsigned int index)\n-{\n-\tuint32_t hub_id;\n-\n-\t/* Grab Hub ID used to parse VPDs */\n-\thub_id = dt_prop_get_u32_def(phb->dt_node, \"ibm,hub-id\", 0);\n-\n-\t/* Process the pcie slot entries from the lx vpd lid */\n-\tlxvpd_process_slot_entries(phb, dt_root, hub_id, index);\n-}\n-\n static uint32_t ibm_fsp_occ_timeout(void)\n {\n \t/* Use a fixed 60s value for now */\n@@ -554,9 +217,9 @@ DECLARE_PLATFORM(firenze) = {\n \t.exit\t\t\t= ibm_fsp_exit,\n \t.cec_power_down\t\t= ibm_fsp_cec_power_down,\n \t.cec_reboot\t\t= ibm_fsp_cec_reboot,\n-\t.pci_setup_phb\t\t= firenze_setup_phb,\n-\t.pci_get_slot_info\t= firenze_get_slot_info,\n-\t.pci_probe_complete\t= firenze_send_pci_inventory,\n+\t.pci_setup_phb\t\t= firenze_pci_setup_phb,\n+\t.pci_get_slot_info\t= firenze_pci_get_slot_info,\n+\t.pci_probe_complete\t= firenze_pci_send_inventory,\n \t.nvram_info\t\t= fsp_nvram_info,\n \t.nvram_start_read\t= fsp_nvram_start_read,\n \t.nvram_write\t\t= fsp_nvram_write,\n@@ -566,4 +229,4 @@ DECLARE_PLATFORM(firenze) = {\n \t.resource_loaded\t= fsp_resource_loaded,\n \t.sensor_read\t\t= ibm_fsp_sensor_read,\n \t.terminate\t\t= ibm_fsp_terminate,\n-} ;\n+};\ndiff --git a/platforms/ibm-fsp/ibm-fsp.h b/platforms/ibm-fsp/ibm-fsp.h\nindex 3b24b5b..3f6e9c5 100644\n--- a/platforms/ibm-fsp/ibm-fsp.h\n+++ b/platforms/ibm-fsp/ibm-fsp.h\n@@ -30,4 +30,17 @@ extern int elog_fsp_commit(struct errorlog *buf);\n extern int64_t ibm_fsp_sensor_read(uint32_t sensor_hndl, int token,\n \t\t\t\tuint32_t *sensor_data);\n \n+/* Apollo PCI support */\n+extern void apollo_pci_setup_phb(struct phb *phb,\n+\t\t\t\t unsigned int index);\n+extern void apollo_pci_get_slot_info(struct phb *phb,\n+\t\t\t\t struct pci_device *pd);\n+\n+/* Firenze PCI support */\n+extern void firenze_pci_send_inventory(void);\n+extern void firenze_pci_setup_phb(struct phb *phb,\n+\t\t\t\t unsigned int index);\n+extern void firenze_pci_get_slot_info(struct phb *phb,\n+\t\t\t\t struct pci_device *pd);\n+\n #endif /* __IBM_FSP_COMMON_H */\ndiff --git a/platforms/ibm-fsp/lxvpd.c b/platforms/ibm-fsp/lxvpd.c\nindex 542c49a..1796013 100644\n--- a/platforms/ibm-fsp/lxvpd.c\n+++ b/platforms/ibm-fsp/lxvpd.c\n@@ -13,11 +13,6 @@\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n-/*\n- * LXVPD support\n- *\n- */\n-\n \n #include <skiboot.h>\n #include <device.h>\n@@ -28,31 +23,35 @@\n \n #include \"lxvpd.h\"\n \n-struct lxvpd_slot_info {\n-\tuint8_t switch_id;\n-\tuint8_t vswitch_id;\n-\tuint8_t dev_id;\n-\tstruct pci_slot_info\tps;\n-};\n+/* Debugging options */\n+#define LXVPD_DBG(fmt, a...)\tprlog(PR_DEBUG, \"LXVPD: \" fmt, ##a)\n+#define LXVPD_INFO(fmt, a...)\tprlog(PR_INFO, \"LXVPD: \" fmt, ##a)\n+#define LXVPD_WARN(fmt, a...)\tprlog(PR_WARNING, \"LXVPD: \" fmt, ##a)\n+#define LXVPD_ERR(fmt, a...)\tprlog(PR_ERR, \"LXVPD: \" fmt, ##a)\n \n /*\n- * XXX TODO: Add 1006 maps to add function loc codes and loc code maps\n- * (ie. -Tn part of the location code) \n+ * Currently, the lxvpd PCI slot struct is shared by multiple\n+ * platforms (Apollo and Firenze), but each slot still has\n+ * platform specific features. In order for unified data structs,\n+ * \"struct lxvpd_slot\" is expected to be embedded in platform\n+ * PCI slot struct. \"entry_size\" indicates the size of platform\n+ * specific PCI slot instance.\n */\n-struct lxvpd_slot_info_data {\n-\tuint8_t\t\t\tnum_slots;\n-\tstruct lxvpd_slot_info\tinfo[];\n+struct lxvpd_pci_slot_data {\n+\tuint8_t\t\tnum_slots;\n+\tint32_t\t\tentry_size;\t/* Size of platform PCI slot */\n+\tvoid\t\t*slots;\t\t/* Data of platform PCI slots */\n };\n \n static bool lxvpd_supported_slot(struct phb *phb, struct pci_device *pd)\n {\n-\t/* PCI/PCI-X we only support top level PHB with NULL \"pd\" */\n-\tif (phb->phb_type < phb_type_pcie_v1)\n-\t\treturn pd == NULL;\n+\t/* PHB should always be valid */\n+\tif (!phb)\n+\t\treturn false;\n \n-\t/* Now we have PCI Express, we should never have a NULL \"pd\" */\n+\t/* We expect platform slot for root complex */\n \tif (!pd)\n-\t\treturn false;\n+\t\treturn true;\n \n \t/* We support the root complex at the top level */\n \tif (pd->dev_type == PCIE_TYPE_ROOT_PORT && !pd->parent)\n@@ -78,174 +77,214 @@ static bool lxvpd_supported_slot(struct phb *phb, struct pci_device *pd)\n \treturn false;\n }\n \n-void lxvpd_get_slot_info(struct phb *phb, struct pci_device * pd)\n+void *lxvpd_get_slot(struct pci_slot *slot)\n {\n-\tstruct lxvpd_slot_info_data *sdata = phb->platform_data;\n+\tstruct phb *phb = slot->phb;\n+\tstruct pci_device *pd = slot->pd;\n+\tstruct lxvpd_pci_slot_data *sdata = phb->platform_data;\n+\tstruct lxvpd_pci_slot *s = NULL;\n+\tuint8_t slot_num = pd ? ((pd->bdfn >> 3) & 0x1f) : 0xff;\n \tbool is_phb = (pd && pd->parent) ? false : true;\n-\tbool entry_found = false;\n-\tuint8_t idx;\n+\tuint8_t index;\n \n \t/* Check if we have slot info */\n-\tif (!sdata)\n-\t\treturn;\n+\tif (!sdata) {\n+\t\tLXVPD_DBG(\"PHB%04x not have VPD data\\n\",\n+\t\t\t phb->opal_id);\n+\t\treturn NULL;\n+\t}\n \n-\tprlog(PR_TRACE, \"LXVPD: Get Slot Info PHB%d pd=%x\\n\", phb->opal_id,\n-\t pd ? pd->bdfn : 0);\n+\t/* Platform slot attached ? */\n+\ts = slot->data;\n+\tif (s) {\n+\t\tLXVPD_DBG(\"Slot %016llx had platform data [%s]\\n\",\n+\t\t\t slot->id, s->label);\n+\t\treturn s;\n+\t}\n \n \t/*\n-\t * This code only handles PHBs and PCIe switches at the top level.\n-\t *\n-\t * We do not handle any other switch nor any other type of PCI/PCI-X\n-\t * bridge.\n+\t * This code only handles PHBs and PCIe switches at the\n+\t * top level. We do not handle any other switch nor any\n+\t * other type of PCI/PCI-X bridge. Generally, we have\n+\t * more strict rules to support slot than PCI core.\n \t */\n \tif (!lxvpd_supported_slot(phb, pd)) {\n-\t\tprlog(PR_TRACE, \"LXVPD: Unsupported slot\\n\");\n-\t\treturn;\n+\t\tLXVPD_DBG(\"Slot %016llx not supported\\n\",\n+\t\t\t slot->id);\n+\t\treturn NULL;\n \t}\n \n-\t/* Iterate the slot map */\n-\tfor (idx = 0; idx <= sdata->num_slots; idx++) {\n-\t\tstruct lxvpd_slot_info *info = &sdata->info[idx];\n-\t\tuint8_t pd_dev = (pd->bdfn >> 3) & 0x1f;\n+\t/* Iterate the platform slot array */\n+\tfor (index = 0; index < sdata->num_slots; index++) {\n+\t\ts = sdata->slots + (index * sdata->entry_size);\n \n \t\t/* Match PHB with switch_id == 0 */\n-\t\tif (is_phb && info->switch_id == 0) {\n-\t\t\tentry_found = true;\n-\t\t\tbreak;\n+\t\tif (is_phb && s->switch_id == 0) {\n+\t\t\tslot->data = s;\n+\t\t\ts->pci_slot = slot;\n+\t\t\tLXVPD_DBG(\"Found [%s] for PHB slot %016llx\\n\",\n+\t\t\t\t s->label, slot->id);\n+\n+\t\t\treturn s;\n \t\t}\n \n \t\t/* Match switch port with switch_id != 0 */\n-\t\tif (!is_phb && info->switch_id !=0 && info->dev_id == pd_dev) {\n-\t\t\tentry_found = true;\n-\t\t\tbreak;\n+\t\tif (!is_phb && s->switch_id != 0 && s->dev_id == slot_num) {\n+\t\t\tslot->data = s;\n+\t\t\ts->pci_slot = slot;\n+\t\t\tLXVPD_DBG(\"Found [%s] for slot %016llx\\n\",\n+\t\t\t\t s->label, slot->id);\n+\n+\t\t\treturn s;\n \t\t}\n \t}\n \n-\tif (entry_found) {\n-\t\tpd->slot_info = &sdata->info[idx].ps;\n-\t\tprlog(PR_TRACE, \"PCI: PCIE Slot Info: \\n\"\n-\t\t \" Label %s\\n\"\n-\t\t \" Pluggable 0x%x\\n\"\n-\t\t \" Power Ctl 0x%x\\n\"\n-\t\t \" Wired Lanes 0x%x\\n\"\n-\t\t \" Bus Clock 0x%x\\n\"\n-\t\t \" Connector 0x%x\\n\"\n-\t\t \" Slot Index %d\\n\",\n-\t\t pd->slot_info->label,\n-\t\t pd->slot_info->pluggable?1:0,\n-\t\t pd->slot_info->power_ctl?1:0,\n-\t\t pd->slot_info->wired_lanes,\n-\t\t pd->slot_info->bus_clock,\n-\t\t pd->slot_info->connector_type,\n-\t\t pd->slot_info->slot_index);\n-\t} else {\n-\t\tprlog(PR_TRACE, \"PCI: PCIE Slot Info Not Found\\n\");\n-\t}\n+\tLXVPD_DBG(\"No data found for %sslot %016llx\\n\",\n+\t\t is_phb ? \"PHB \" : \" \", slot->id);\n+\treturn NULL;\n }\n \n-static struct lxvpd_slot_info *lxvpd_alloc_slot_info(struct phb *phb, int count)\n+void lxvpd_extract_info(struct pci_slot *slot, struct lxvpd_pci_slot *s)\n {\n-\tstruct lxvpd_slot_info_data *data;\n+\tslot->pluggable = s->pluggable ? 1 : 0;\n+\tslot->power_ctl = s->power_ctl ? 1 : 0;\n+\tslot->power_led_ctl = s->pwr_led_ctl;\n+\tslot->attn_led_ctl = s->attn_led_ctl;\n+\tslot->connector_type = s->connector_type;\n+\tslot->card_desc = s->card_desc;\n+\tslot->card_mech = s->card_mech;\n+\tslot->wired_lanes = s->wired_lanes;\n+}\n+\n+static struct lxvpd_pci_slot_data *lxvpd_alloc_slots(struct phb *phb,\n+\t\t\t\t\t\t uint8_t count,\n+\t\t\t\t\t\t uint32_t slot_size)\n+{\n+\tstruct lxvpd_pci_slot_data *sdata;\n \n-\tdata = zalloc(sizeof(struct lxvpd_slot_info_data) *\n-\t\t count * sizeof(struct lxvpd_slot_info));\n-\tassert(data);\n-\tdata->num_slots = count;\n-\tphb->platform_data = data;\n+\tsdata = zalloc(sizeof(struct lxvpd_pci_slot_data) + count * slot_size);\n+\tassert(sdata);\n+\tsdata->num_slots = count;\n+\tsdata->entry_size = slot_size;\n+\tsdata->slots = sdata + 1;\n+\tphb->platform_data = sdata;\n \n-\treturn data->info;\n+\treturn sdata;\n }\n \n-static void lxvpd_parse_1004_map(struct phb *phb, const uint8_t *sm, uint8_t sz)\n+static void lxvpd_format_label(char *dst, const char *src, size_t len)\n {\n-\tconst struct pci_slot_entry_1004 *entry = NULL;\n-\tstruct lxvpd_slot_info *slot_info, *info;\n-\tuint8_t num_slots, slot, idx;\n+\tint i;\n \n-\tnum_slots = (sz / sizeof(struct pci_slot_entry_1004));\n-\tslot_info = lxvpd_alloc_slot_info(phb, num_slots);\n+\tmemcpy(dst, src, len);\n+\n+\t/* Remove blank suffix */\n+\tfor (i = strlen(dst) - 1; i >= 0; i--) {\n+\t\tif (dst[i] != ' ')\n+\t\t\tbreak;\n+\n+\t\tdst[i] = 0;\n+\t}\n+}\n+\n+static void lxvpd_parse_1004_map(struct phb *phb,\n+\t\t\t\t const uint8_t *sm,\n+\t\t\t\t uint8_t size,\n+\t\t\t\t uint32_t slot_size)\n+{\n+\tstruct lxvpd_pci_slot_data *sdata;\n+\tstruct lxvpd_pci_slot *s;\n+\tconst struct pci_slot_entry_1004 *entry;\n+\tuint8_t num_slots, slot;\n+\n+\tnum_slots = (size / sizeof(struct pci_slot_entry_1004));\n+\tsdata = lxvpd_alloc_slots(phb, num_slots, slot_size);\n \n \t/* Iterate through the entries in the keyword */\n \tentry = (const struct pci_slot_entry_1004 *)sm;\n-\tfor (slot = 0; slot < num_slots; slot++) {\n-\t\tinfo = &slot_info[slot];\n+\tfor (slot = 0; slot < num_slots; slot++, entry++) {\n+\t\ts = sdata->slots + slot * sdata->entry_size;\n+\n+\t\t/* Figure out PCI slot info */\n+\t\tlxvpd_format_label(s->label, entry->label, 3);\n+\t\ts->slot_index = entry->slot_index;\n+\t\ts->switch_id = entry->pba >> 4;\n+\t\ts->vswitch_id = entry->pba & 0xf;\n+\t\ts->dev_id = entry->sba;\n+\t\ts->pluggable = ((entry->p0.byte & 0x20) == 0);\n+\t\ts->power_ctl = ((entry->p0.power_ctl & 0x40) == 1);\n+\t\ts->bus_clock = entry->p2.bus_clock - 4;\n+\t\ts->connector_type = entry->p2.connector_type - 5;\n+\t\ts->card_desc = entry->p3.byte >> 6;\n+\t\tif (entry->p3.byte < 0xc0)\n+\t\t\ts->card_desc -= 4;\n+\t\ts->card_mech = (entry->p3.byte >> 4) & 0x3;\n+\t\ts->pwr_led_ctl = (entry->p3.byte & 0xf) >> 2;\n+\t\ts->attn_led_ctl = entry->p3.byte & 0x3;\n \n-\t\t/* Put slot info into pci device structure */\n-\t\tinfo->switch_id = entry->pba >> 4;\n-\t\tinfo->vswitch_id = entry->pba &0xf;\n-\t\tinfo->dev_id = entry->sba;\n-\t\tfor (idx = 0; idx < 3; idx++)\n-\t\t\tinfo->ps.label[idx] = entry->label[idx];\n-\t\tinfo->ps.label[3] = 0;\n-\t\tinfo->ps.pluggable = ((entry->p0.byte & 0x20) == 0);\n-\t\tinfo->ps.power_ctl = ((entry->p0.power_ctl & 0x40) == 1);\n \t\tswitch(entry->p1.wired_lanes) {\n-\t\tcase 1: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_32; break;\n+\t\tcase 1: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_32; break;\n \t\tcase 2: /* fall through */\n-\t\tcase 3: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_64; break;\n-\t\tcase 4: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X1; break;\n-\t\tcase 5: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X4; break;\n-\t\tcase 6: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X8; break;\n-\t\tcase 7: info->ps.wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X16; break;\n+\t\tcase 3: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIX_64; break;\n+\t\tcase 4: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X1; break;\n+\t\tcase 5: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X4; break;\n+\t\tcase 6: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X8; break;\n+\t\tcase 7: s->wired_lanes = PCI_SLOT_WIRED_LANES_PCIE_X16; break;\n \t\tdefault:\n-\t\t\tinfo->ps.wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;\n+\t\t\ts->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;\n \t\t}\n-\t\tinfo->ps.wired_lanes = (entry->p1.wired_lanes - 3);\n-\t\tinfo->ps.bus_clock = (entry->p2.bus_clock - 4);\n-\t\tinfo->ps.connector_type = (entry->p2.connector_type - 5);\n-\t\tif (entry->p3.byte < 0xC0)\n-\t\t\tinfo->ps.card_desc = ((entry->p3.byte >> 6) - 4) ;\n-\t\telse\n-\t\t\tinfo->ps.card_desc = (entry->p3.byte >> 6);\n-\t\tinfo->ps.card_mech = ((entry->p3.byte >> 4) & 0x3);\n-\t\tinfo->ps.pwr_led_ctl = ((entry->p3.byte & 0xF) >> 2);\n-\t\tinfo->ps.attn_led_ctl = (entry->p3.byte & 0x3);\n-\t\tinfo->ps.slot_index = entry->slot_index;\n-\t\tentry++;\n+\n+\t\tLXVPD_DBG(\"1004 Platform data [%s] %02x %02x on PHB%04x\\n\",\n+\t\t\t s->label, s->switch_id, s->dev_id, phb->opal_id);\n \t}\n }\n \n-static void lxvpd_parse_1005_map(struct phb *phb, const uint8_t *sm, uint8_t sz)\n+static void lxvpd_parse_1005_map(struct phb *phb,\n+\t\t\t\t const uint8_t *sm,\n+\t\t\t\t uint8_t size,\n+\t\t\t\t uint32_t slot_size)\n {\n-\tconst struct pci_slot_entry_1005 *entry = NULL;\n-\tstruct lxvpd_slot_info *slot_info, *info;\n-\tuint8_t num_slots, slot, idx;\n+\tstruct lxvpd_pci_slot_data *sdata;\n+\tstruct lxvpd_pci_slot *s;\n+\tconst struct pci_slot_entry_1005 *entry;\n+\tuint8_t num_slots, slot;\n \n-\tnum_slots = (sz / sizeof(struct pci_slot_entry_1005));\n-\tslot_info = lxvpd_alloc_slot_info(phb, num_slots);\n+\tnum_slots = (size / sizeof(struct pci_slot_entry_1005));\n+\tsdata = lxvpd_alloc_slots(phb, num_slots, slot_size);\n \n \t/* Iterate through the entries in the keyword */\n \tentry = (const struct pci_slot_entry_1005 *)sm;\n-\tfor (slot = 0; slot < num_slots; slot++) {\n-\t\tinfo = &slot_info[slot];\n+\tfor (slot = 0; slot < num_slots; slot++, entry++) {\n+\t\ts = sdata->slots + slot * sdata->entry_size;\n \n \t\t/* Put slot info into pci device structure */\n-\t\tinfo->switch_id = entry->pba >> 4;\n-\t\tinfo->vswitch_id = entry->pba &0xf;\n-\t\tinfo->dev_id = entry->switch_device_id;\n-\t\tfor (idx = 0; idx < 8; idx++)\n-\t\t\tinfo->ps.label[idx] = entry->label[idx];\n-\t\tinfo->ps.label[8] = 0;\n-\t\tinfo->ps.pluggable = (entry->p0.pluggable == 0);\n-\t\tinfo->ps.power_ctl = entry->p0.power_ctl;\n-\t\tinfo->ps.wired_lanes = entry->p1.wired_lanes;\n-\t\tif (info->ps.wired_lanes > PCI_SLOT_WIRED_LANES_PCIE_X32)\n-\t\t\tinfo->ps.wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;\n-\t\tinfo->ps.bus_clock = entry->p2.bus_clock;\n-\t\tinfo->ps.connector_type = entry->p2.connector_type;\n-\t\tinfo->ps.card_desc = (entry->p3.byte >> 6);\n-\t\tinfo->ps.card_mech = ((entry->p3.byte >> 4) & 0x3);\n-\t\tinfo->ps.pwr_led_ctl = ((entry->p3.byte & 0xF) >> 2);\n-\t\tinfo->ps.attn_led_ctl = (entry->p3.byte & 0x3);\n-\t\tinfo->ps.slot_index = entry->slot_index;\n-\t\tentry++;\n+\t\tlxvpd_format_label(s->label, entry->label, 8);\n+\t\ts->slot_index = entry->slot_index;\n+\t\ts->switch_id = entry->pba >> 4;\n+\t\ts->vswitch_id = entry->pba & 0xf;\n+\t\ts->dev_id = entry->switch_device_id;\n+\t\ts->pluggable = (entry->p0.pluggable == 0);\n+\t\ts->power_ctl = entry->p0.power_ctl;\n+\t\ts->bus_clock = entry->p2.bus_clock;\n+\t\ts->connector_type = entry->p2.connector_type;\n+\t\ts->card_desc = entry->p3.byte >> 6;\n+\t\ts->card_mech = (entry->p3.byte >> 4) & 0x3;\n+\t\ts->pwr_led_ctl = (entry->p3.byte & 0xf) >> 2;\n+\t\ts->attn_led_ctl = entry->p3.byte & 0x3;\n+\t\ts->wired_lanes = entry->p1.wired_lanes;\n+\t\tif (s->wired_lanes > PCI_SLOT_WIRED_LANES_PCIE_X32)\n+\t\t\ts->wired_lanes = PCI_SLOT_WIRED_LANES_UNKNOWN;\n+\n+\t\tLXVPD_DBG(\"1005 Platform data [%s] %02x %02x on PHB%04x\\n\",\n+\t\t\t s->label, s->switch_id, s->dev_id, phb->opal_id);\n \t}\n }\n \n void lxvpd_process_slot_entries(struct phb *phb,\n \t\t\t\tstruct dt_node *node,\n \t\t\t\tuint8_t chip_id,\n-\t\t\t\tuint8_t index)\n+\t\t\t\tuint8_t index,\n+\t\t\t\tuint32_t slot_size)\n {\n \tconst void *lxvpd;\n \tconst uint8_t *pr_rec, *pr_end, *sm;\n@@ -262,24 +301,23 @@ void lxvpd_process_slot_entries(struct phb *phb,\n \t/* Get LX VPD pointer */\n \tlxvpd = dt_prop_get_def_size(node, \"ibm,io-vpd\", NULL, &lxvpd_size);\n \tif (!lxvpd) {\n-\t\tprintf(\"LXVPD: LX VPD not found for %s in %p\\n\",\n-\t\t record, phb->dt_node);\n+\t\tLXVPD_WARN(\"No data found for PHB%04x %s\\n\",\n+\t\t\t phb->opal_id, record);\n \t\treturn;\n \t}\n \n \tpr_rec = vpd_find_record(lxvpd, lxvpd_size, record, &pr_size);\n \tif (!pr_rec) {\n-\t\tprintf(\"LXVPD: %s record not found in LX VPD in %p\\n\",\n-\t\t record, phb->dt_node);\n+\t\tLXVPD_WARN(\"Record %s not found on PHB%04x\\n\",\n+\t\t\t record, phb->opal_id);\n \t\treturn;\n \t}\n-\tpr_end = pr_rec + pr_size;\n \n-\tprlog(PR_TRACE, \"LXVPD: %s record for PHB%d is %ld bytes\\n\",\n-\t record, phb->opal_id, pr_size);\n-\n-\t/* As long as there's still something in the PRxy record... */\n-\twhile(pr_rec < pr_end) {\n+\t/* As long as there's still something in the PRxy record */\n+\tLXVPD_DBG(\"PHB%04x record %s has %ld bytes\\n\",\n+\t\t phb->opal_id, record, pr_size);\n+\tpr_end = pr_rec + pr_size;\n+\twhile (pr_rec < pr_end) {\n \t\tpr_size = pr_end - pr_rec;\n \n \t\t/* Find the next MF keyword */\n@@ -288,24 +326,56 @@ void lxvpd_process_slot_entries(struct phb *phb,\n \t\tsm = vpd_find_keyword(pr_rec, pr_size, \"SM\", &sm_sz);\n \t\tif (!mf || !sm) {\n \t\t\tif (!found)\n-\t\t\t\tprintf(\"LXVPD: Slot Map keyword %s not found\\n\",\n-\t\t\t\t record);\n+\t\t\t\tLXVPD_WARN(\"Slot Map keyword %s not found\\n\",\n+\t\t\t\t\t record);\n \t\t\treturn;\n \t\t}\n-\t\tprlog(PR_TRACE, \"LXVPD: Found 0x%04x map...\\n\", *mf);\n \n+\t\tLXVPD_DBG(\"Found 0x%04x map...\\n\", *mf);\n \t\tswitch (*mf) {\n \t\tcase 0x1004:\n-\t\t\tlxvpd_parse_1004_map(phb, sm + 1, sm_sz - 1);\n+\t\t\tlxvpd_parse_1004_map(phb, sm + 1, sm_sz - 1, slot_size);\n \t\t\tfound = true;\n \t\t\tbreak;\n \t\tcase 0x1005:\n-\t\t\tlxvpd_parse_1005_map(phb, sm + 1, sm_sz - 1);\n+\t\t\tlxvpd_parse_1005_map(phb, sm + 1, sm_sz - 1, slot_size);\n \t\t\tfound = true;\n \t\t\tbreak;\n \t\t\t/* Add support for 0x1006 maps ... */\n \t\t}\n+\n \t\tpr_rec = sm + sm_sz;\n \t}\n }\n \n+void lxvpd_add_slot_properties(struct pci_slot *slot,\n+\t\t\t struct dt_node *np)\n+{\n+\tstruct phb *phb = slot->phb;\n+\tstruct lxvpd_pci_slot *s = slot->data;\n+\tchar loc_code[LOC_CODE_SIZE];\n+\tsize_t base_loc_code_len, slot_label_len;\n+\n+\t/* Check if we have platform specific slot */\n+\tif (!s || !np)\n+\t\treturn;\n+\n+\t/* Check PHB base location code */\n+\tif (!phb->base_loc_code)\n+\t\treturn;\n+\n+\t/* Check location length is valid */\n+\tbase_loc_code_len = strlen(phb->base_loc_code);\n+\tslot_label_len = strlen(s->label);\n+\tif ((base_loc_code_len + slot_label_len + 1) >= LOC_CODE_SIZE)\n+\t\treturn;\n+\n+\t/* Location code */\n+\tstrcpy(loc_code, phb->base_loc_code);\n+\tstrcat(loc_code, \"-\");\n+\tstrcat(loc_code, s->label);\n+\tdt_add_property(np, \"ibm,slot-location-code\",\n+\t\t\tloc_code, strlen(loc_code) + 1);\n+\tdt_add_property_string(np, \"ibm,slot-label\",\n+\t\t\t s->label);\n+}\ndiff --git a/platforms/ibm-fsp/lxvpd.h b/platforms/ibm-fsp/lxvpd.h\nindex dbb9513..c7ca21b 100644\n--- a/platforms/ibm-fsp/lxvpd.h\n+++ b/platforms/ibm-fsp/lxvpd.h\n@@ -23,8 +23,6 @@\n #define LX_VPD_1S4U_BACKPLANE\t0x3100040100300043ull\n #define LX_VPD_2S4U_BACKPLANE\t0x3100040100300044ull\n \n-/* P8 PCI Slot Entry Definitions -- 1005 */\n-\n struct slot_p0 {\n \tunion {\n \t\tuint8_t byte;\n@@ -83,6 +81,7 @@ struct pci_slot_entry_1004 {\n \tuint8_t max_slot_power;\n };\n \n+/* P8 PCI Slot Entry Definitions -- 1005 */\n struct pci_slot_entry_1005 {\n \tunion {\n \t\tuint8_t pba;\n@@ -106,12 +105,30 @@ struct pci_slot_entry_1005 {\n \tuint8_t rsvd_22[2];\n };\n \n-struct phb;\n-\n-extern void lxvpd_process_slot_entries(struct phb *phb,\n-\t\t\t\t struct dt_node *node,\n-\t\t\t\t uint8_t chip_id, uint8_t index);\n-\n-extern void lxvpd_get_slot_info(struct phb *phb, struct pci_device * pd);\n+struct lxvpd_pci_slot {\n+\tstruct pci_slot\t*pci_slot;\n+\tuint8_t\t\tswitch_id;\n+\tuint8_t\t\tvswitch_id;\n+\tuint8_t\t\tdev_id;\n+\tchar\t\tlabel[9];\n+\tbool\t\tpluggable;\n+\tbool\t\tpower_ctl;\n+\tuint8_t\t\twired_lanes;\n+\tuint8_t\t\tbus_clock;\n+\tuint8_t\t\tconnector_type;\n+\tuint8_t\t\tcard_desc;\n+\tuint8_t\t\tcard_mech;\n+\tuint8_t\t\tpwr_led_ctl;\n+\tuint8_t\t\tattn_led_ctl;\n+\tuint8_t\t\tslot_index;\n+};\n \n+extern void lxvpd_process_slot_entries(struct phb *phb, struct dt_node *node,\n+\t\t\t\t uint8_t chip_id, uint8_t index,\n+\t\t\t\t uint32_t slot_size);\n+extern void *lxvpd_get_slot(struct pci_slot *slot);\n+extern void lxvpd_extract_info(struct pci_slot *slot,\n+\t\t\t struct lxvpd_pci_slot *s);\n+extern void lxvpd_add_slot_properties(struct pci_slot *slot,\n+\t\t\t\t struct dt_node *np);\n #endif /* __LXVPD_H */\n", "prefixes": [ "v12", "18/23" ] }