Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/808014/?format=api
{ "id": 808014, "url": "http://patchwork.ozlabs.org/api/patches/808014/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pci/patch/1504154670-24608-4-git-send-email-oza.oza@broadcom.com/", "project": { "id": 28, "url": "http://patchwork.ozlabs.org/api/projects/28/?format=api", "name": "Linux PCI development", "link_name": "linux-pci", "list_id": "linux-pci.vger.kernel.org", "list_email": "linux-pci@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1504154670-24608-4-git-send-email-oza.oza@broadcom.com>", "list_archive_url": null, "date": "2017-08-31T04:44:30", "name": "[v5,3/3] PCI: iproc: Implement PCI hotplug support", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "8ae01d6f9b11b0b622e821535fcbce3d4509782d", "submitter": { "id": 71219, "url": "http://patchwork.ozlabs.org/api/people/71219/?format=api", "name": "Oza Pawandeep", "email": "oza.oza@broadcom.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-pci/patch/1504154670-24608-4-git-send-email-oza.oza@broadcom.com/mbox/", "series": [ { "id": 740, "url": "http://patchwork.ozlabs.org/api/series/740/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pci/list/?series=740", "date": "2017-08-31T04:44:27", "name": "PCI hotplug feature", "version": 5, "mbox": "http://patchwork.ozlabs.org/series/740/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/808014/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/808014/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linux-pci-owner@vger.kernel.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-pci-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "ozlabs.org; dkim=pass (1024-bit key;\n\tunprotected) header.d=broadcom.com header.i=@broadcom.com\n\theader.b=\"CNVx+YID\"; dkim-atps=neutral" ], "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xjVCp35KBz9s81\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 31 Aug 2017 14:44:54 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751074AbdHaEou (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tThu, 31 Aug 2017 00:44:50 -0400", "from mail-qt0-f170.google.com ([209.85.216.170]:34769 \"EHLO\n\tmail-qt0-f170.google.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1751016AbdHaEos (ORCPT\n\t<rfc822; linux-pci@vger.kernel.org>); Thu, 31 Aug 2017 00:44:48 -0400", "by mail-qt0-f170.google.com with SMTP id u11so35524647qtu.1\n\tfor <linux-pci@vger.kernel.org>; Wed, 30 Aug 2017 21:44:48 -0700 (PDT)", "from anjanavk-OptiPlex-7010.dhcp.avagotech.net ([192.19.237.250])\n\tby smtp.gmail.com with ESMTPSA id\n\ti13sm4769713qke.7.2017.08.30.21.44.42\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 30 Aug 2017 21:44:46 -0700 (PDT)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=broadcom.com; s=google;\n\th=from:to:subject:date:message-id:in-reply-to:references;\n\tbh=ntNel+zmmbVDFeJfLEsbq0RGvnwXFRop+BNsp2N2/Fw=;\n\tb=CNVx+YID5A33tU1NSLxMcINRClrZ08zOZgyAG6RiWUNaJalZhc/bO8asvim5qwoEE9\n\t/pi8nDV7S59IU8x5NyjsFZKcNzWaAiT3nXkF3ScSafJma88i/FP9l7ixzMDpo4fzIejf\n\toQNGPlU2uXzxdmjsbZPiKGEHQIEFCOD66YGTM=", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=ntNel+zmmbVDFeJfLEsbq0RGvnwXFRop+BNsp2N2/Fw=;\n\tb=PsIfVxS+Ar7Z8hMeg1yP35BNtissM64lQDJDzYWZdK9rOYHJ7bLcV/x4OR51/jxvl+\n\t7UqJUNY3v1kbVWMBAobLqOVAK1FLk9K6Jitbq3TJtPWiSSI7QkZE7VfueWrkqyd/TVhJ\n\t5NlCA9jSee/ZLEwIM4avGtLpOSPg2cyissUB3CrgaGKJLfhzXq/s2K7LpR41XAPeReqA\n\tldVrKqfb7CAjLW78E9v1Yybo69+ZoLMN8CxdLozICrtsAtaQb5R05rUxOe8PDBghLh0L\n\tkMawAxrIJ7kX6I+6thPOzygbdBM2Oe8lhL7OeWL+su7918RvvhKJvOFacNME9SufLSL4\n\tjzLw==", "X-Gm-Message-State": "AHYfb5jNaYCcoZ3ISxWmfCS+w3nVuK0hF7TvfdWgTNDQFwnoV6CzG5Gj\n\tBstbeAS4pJKc8ezN", "X-Received": "by 10.200.13.142 with SMTP id s14mr5232059qti.162.1504154687498; \n\tWed, 30 Aug 2017 21:44:47 -0700 (PDT)", "From": "Oza Pawandeep <oza.oza@broadcom.com>", "To": "Bjorn Helgaas <bhelgaas@google.com>, <helgaas@kernel.org>,\n\tRob Herring <robh+dt@kernel.org>, Mark Rutland <mark.rutland@arm.com>,\n\tRay Jui <rjui@broadcom.com>, Scott Branden <sbranden@broadcom.com>,\n\tJon Mason <jonmason@broadcom.com>, bcm-kernel-feedback-list@broadcom.com,\n\tOza Pawandeep <oza.oza@broadcom.com>,\n\tAndy Gospodarek <gospo@broadcom.com>,\n\tlinux-pci@vger.kernel.org, devicetree@vger.kernel.org,\n\tlinux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org,\n\tOza Pawandeep <oza.pawandeep@gmail.com>", "Subject": "[PATCH v5 3/3] PCI: iproc: Implement PCI hotplug support", "Date": "Thu, 31 Aug 2017 10:14:30 +0530", "Message-Id": "<1504154670-24608-4-git-send-email-oza.oza@broadcom.com>", "X-Mailer": "git-send-email 1.9.1", "In-Reply-To": "<1504154670-24608-1-git-send-email-oza.oza@broadcom.com>", "References": "<1504154670-24608-1-git-send-email-oza.oza@broadcom.com>", "Sender": "linux-pci-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<linux-pci.vger.kernel.org>", "X-Mailing-List": "linux-pci@vger.kernel.org" }, "content": "This patch implements PCI hotplug support for iproc family chipsets.\n\niproc based SOC (e.g. Stingray) does not have hotplug controller\nintegrated.\nHence, standard PCI hotplug framework hooks can-not be used.\ne.g. controlled power up/down of slot.\n\nThe mechanism, for e.g. Stingray has adopted for PCI hotplug is as follows:\nPCI present lines are input to GPIOs depending on the type of\nconnector (x2, x4, x8).\n\nGPIO array needs to be present if hotplug is supported.\nHW implementation is SOC/Board specific, and also it depends on how\nadd-in card is designed\n(e.g. how many present pins are implemented).\n\nIf x8 card is connected, then it might be possible that all the\n3 present pins could go low, or at least one pin goes low.\nIf x4 card is connected, then it might be possible that 2 present\npins go low, or at least one pin goes low.\n\nThe implementation essentially takes care of following:\n> Initializing hotplug irq thread.\n> Detecting the endpoint device based on link state.\n> Handling PERST and detecting the plugged devices.\n> Ordered Hot plug-out, where User is expected\n to write 1 to /sys/bus/pci/devices/<pci_dev>/remove\n> Handling spurious interrupt\n> Handling multiple interrupts and makes sure that card is\n enumerated only once.\n\nSigned-off-by: Oza Pawandeep <oza.oza@broadcom.com>\nReviewed-by: Ray Jui <ray.jui@broadcom.com>", "diff": "diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c\nindex a5073a9..6287a43 100644\n--- a/drivers/pci/host/pcie-iproc-platform.c\n+++ b/drivers/pci/host/pcie-iproc-platform.c\n@@ -92,6 +92,9 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)\n \t\tpcie->need_ob_cfg = true;\n \t}\n \n+\tif (of_property_read_bool(np, \"slot-pluggable\"))\n+\t\tpcie->enable_hotplug = true;\n+\n \t/* PHY use is optional */\n \tpcie->phy = devm_phy_get(dev, \"pcie-phy\");\n \tif (IS_ERR(pcie->phy)) {\ndiff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c\nindex 8bd5e54..2b4d830 100644\n--- a/drivers/pci/host/pcie-iproc.c\n+++ b/drivers/pci/host/pcie-iproc.c\n@@ -28,6 +28,7 @@\n #include <linux/of_irq.h>\n #include <linux/of_platform.h>\n #include <linux/phy/phy.h>\n+#include <linux/gpio.h>\n \n #include \"pcie-iproc.h\"\n \n@@ -65,6 +66,17 @@\n #define PCIE_DL_ACTIVE_SHIFT 2\n #define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT)\n \n+#define CFG_RC_LTSSM 0x1cf8\n+#define CFG_RC_PHY_CTL 0x1804\n+#define CFG_RC_LTSSM_TIMEOUT 1000\n+#define CFG_RC_LTSSM_STATE_MASK 0xff\n+#define CFG_RC_LTSSM_STATE_L1 0x1\n+\n+#define CFG_RC_CLR_LTSSM_HIST_SHIFT 29\n+#define CFG_RC_CLR_LTSSM_HIST_MASK BIT(CFG_RC_CLR_LTSSM_HIST_SHIFT)\n+#define CFG_RC_CLR_RECOV_HIST_SHIFT 31\n+#define CFG_RC_CLR_RECOV_HIST_MASK BIT(CFG_RC_CLR_RECOV_HIST_SHIFT)\n+\n #define APB_ERR_EN_SHIFT 0\n #define APB_ERR_EN BIT(APB_ERR_EN_SHIFT)\n \n@@ -1354,13 +1366,107 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie)\n \treturn 0;\n }\n \n+static bool iproc_pci_hp_check_ltssm(struct iproc_pcie *pcie)\n+{\n+\tstruct pci_bus *bus = pcie->root_bus;\n+\tu32 val, timeout = CFG_RC_LTSSM_TIMEOUT;\n+\n+\t/* Clear LTSSM history. */\n+\tpci_bus_read_config_dword(pcie->root_bus, 0,\n+\t\t\t\t CFG_RC_PHY_CTL, &val);\n+\tpci_bus_write_config_dword(bus, 0, CFG_RC_PHY_CTL,\n+\t\t\t\t val | CFG_RC_CLR_RECOV_HIST_MASK |\n+\t\t\t\t CFG_RC_CLR_LTSSM_HIST_MASK);\n+\t/* write back the origional value. */\n+\tpci_bus_write_config_dword(bus, 0, CFG_RC_PHY_CTL, val);\n+\n+\tdo {\n+\t\tpci_bus_read_config_dword(pcie->root_bus, 0,\n+\t\t\t\t\t CFG_RC_LTSSM, &val);\n+\t\t/* check link state to see if link moved to L1 state. */\n+\t\tif ((val & CFG_RC_LTSSM_STATE_MASK) ==\n+\t\t CFG_RC_LTSSM_STATE_L1)\n+\t\t\treturn true;\n+\t\ttimeout--;\n+\t\tusleep_range(500, 1000);\n+\t} while (timeout);\n+\n+\treturn false;\n+}\n+\n+static irqreturn_t iproc_pci_hotplug_thread(int irq, void *data)\n+{\n+\tstruct iproc_pcie *pcie = data;\n+\tstruct pci_bus *bus = pcie->root_bus, *child;\n+\tbool link_status;\n+\n+\tiproc_pcie_perst_ctrl(pcie, true);\n+\tiproc_pcie_perst_ctrl(pcie, false);\n+\n+\tlink_status = iproc_pci_hp_check_ltssm(pcie);\n+\n+\tif (link_status &&\n+\t !iproc_pcie_check_link(pcie) &&\n+\t !pcie->ep_is_present) {\n+\t\tpci_rescan_bus(bus);\n+\t\tlist_for_each_entry(child, &bus->children, node)\n+\t\t\tpcie_bus_configure_settings(child);\n+\t\tpcie->ep_is_present = true;\n+\t\tdev_info(pcie->dev,\n+\t\t\t \"PCI Hotplug: <device detected and enumerated>\\n\");\n+\t} else if (link_status && pcie->ep_is_present)\n+\t\t/*\n+\t\t * ep_is_present makes sure, enumuration done only once.\n+\t\t * So it can handle spurious intrrupts, and also if we\n+\t\t * get multiple interrupts for all the implemented pins,\n+\t\t * we handle it only once.\n+\t\t */\n+\t\tdev_info(pcie->dev,\n+\t\t\t \"PCI Hotplug: <device already present>\\n\");\n+\telse {\n+\t\tiproc_pcie_perst_ctrl(pcie, true);\n+\t\tpcie->ep_is_present = false;\n+\t\tdev_info(pcie->dev,\n+\t\t\t \"PCI Hotplug: <device removed>\\n\");\n+\t}\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int iproc_pci_hp_gpio_irq_get(struct iproc_pcie *pcie)\n+{\n+\tstruct gpio_descs *hp_gpiod;\n+\tstruct device *dev = pcie->dev;\n+\tint i;\n+\n+\thp_gpiod = devm_gpiod_get_array(dev, \"prsnt\", GPIOD_IN);\n+\tif (PTR_ERR(hp_gpiod) == -EPROBE_DEFER)\n+\t\treturn -EPROBE_DEFER;\n+\n+\tif (!IS_ERR(hp_gpiod) && (hp_gpiod->ndescs > 0)) {\n+\t\tfor (i = 0; i < hp_gpiod->ndescs; ++i) {\n+\t\t\tgpiod_direction_input(hp_gpiod->desc[i]);\n+\t\t\tif (request_threaded_irq(gpiod_to_irq\n+\t\t\t\t\t\t (hp_gpiod->desc[i]),\n+\t\t\t\t\t\t NULL, iproc_pci_hotplug_thread,\n+\t\t\t\t\t\t IRQF_TRIGGER_FALLING,\n+\t\t\t\t\t\t \"PCI-hotplug\", pcie))\n+\t\t\t\tdev_err(dev,\n+\t\t\t\t\t\"PCI hotplug prsnt: request irq failed\\n\");\n+\t\t\t}\n+\t}\n+\tpcie->ep_is_present = false;\n+\n+\treturn 0;\n+}\n+\n int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)\n {\n \tstruct device *dev;\n \tint ret;\n \tvoid *sysdata;\n-\tstruct pci_bus *child;\n+\tstruct pci_bus *bus, *child;\n \tstruct pci_host_bridge *host = pci_host_bridge_from_priv(pcie);\n+\tbool link_not_active;\n \n \tdev = pcie->dev;\n \n@@ -1386,6 +1492,12 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)\n \t\tgoto err_exit_phy;\n \t}\n \n+\tif (pcie->enable_hotplug) {\n+\t\tret = iproc_pci_hp_gpio_irq_get(pcie);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t}\n+\n \tiproc_pcie_perst_ctrl(pcie, true);\n \tiproc_pcie_perst_ctrl(pcie, false);\n \n@@ -1408,8 +1520,16 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)\n \tsysdata = pcie;\n #endif\n \n-\tret = iproc_pcie_check_link(pcie);\n-\tif (ret) {\n+\tlink_not_active = iproc_pcie_check_link(pcie);\n+\tif (link_not_active && pcie->enable_hotplug) {\n+\t\t/*\n+\t\t * When link is not active and PCI hotplug\n+\t\t * is supported, do not turn off phy, let probe\n+\t\t * go ahead.\n+\t\t */\n+\t\tdev_err(dev, \"no PCIe EP device detected\\n\");\n+\t\tiproc_pcie_perst_ctrl(pcie, true);\n+\t} else if (link_not_active) {\n \t\tdev_err(dev, \"no PCIe EP device detected\\n\");\n \t\tgoto err_power_off_phy;\n \t}\n@@ -1420,24 +1540,34 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)\n \t\tif (iproc_pcie_msi_enable(pcie))\n \t\t\tdev_info(dev, \"not using iProc MSI\\n\");\n \n-\tlist_splice_init(res, &host->windows);\n-\thost->busnr = 0;\n-\thost->dev.parent = dev;\n-\thost->ops = &iproc_pcie_ops;\n-\thost->sysdata = sysdata;\n-\thost->map_irq = pcie->map_irq;\n-\thost->swizzle_irq = pci_common_swizzle;\n+\tif (!link_not_active) {\n+\t\tlist_splice_init(res, &host->windows);\n+\t\thost->busnr = 0;\n+\t\thost->dev.parent = dev;\n+\t\thost->ops = &iproc_pcie_ops;\n+\t\thost->sysdata = sysdata;\n+\t\thost->map_irq = pcie->map_irq;\n+\t\thost->swizzle_irq = pci_common_swizzle;\n+\n+\t\tret = pci_scan_root_bus_bridge(host);\n+\t\tif (ret < 0) {\n+\t\t\tdev_err(dev, \"failed to scan host: %d\\n\", ret);\n+\t\t\tgoto err_power_off_phy;\n+\t\t}\n \n-\tret = pci_scan_root_bus_bridge(host);\n-\tif (ret < 0) {\n-\t\tdev_err(dev, \"failed to scan host: %d\\n\", ret);\n-\t\tgoto err_power_off_phy;\n+\t\tpci_assign_unassigned_bus_resources(host->bus);\n+\t\tpcie->root_bus = host->bus;\n+\t} else {\n+\t\tbus = pci_create_root_bus(dev, 0,\n+\t\t\t\t\t &iproc_pcie_ops, sysdata, res);\n+\t\tif (!bus) {\n+\t\t\tdev_err(dev, \"unable to create PCI root bus\\n\");\n+\t\t\tret = -ENOMEM;\n+\t\t\tgoto err_power_off_phy;\n+\t\t}\n+\t\tpcie->root_bus = bus;\n \t}\n \n-\tpci_assign_unassigned_bus_resources(host->bus);\n-\n-\tpcie->root_bus = host->bus;\n-\n \tlist_for_each_entry(child, &host->bus->children, node)\n \t\tpcie_bus_configure_settings(child);\n \ndiff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h\nindex a6b55ce..e5d0cd4 100644\n--- a/drivers/pci/host/pcie-iproc.h\n+++ b/drivers/pci/host/pcie-iproc.h\n@@ -77,6 +77,10 @@ struct iproc_pcie_ib {\n * @ib: inbound mapping related parameters\n * @ib_map: outbound mapping region related parameters\n *\n+ * @enable_hotplug: indicates PCI hotplug feature is enabled\n+ * @ep_is_present: when PCIe hotplug is enabled, this flag is used to\n+ * indicate whether or not the endpoint device is present\n+ *\n * @need_msi_steer: indicates additional configuration of the iProc PCIe\n * controller is required to steer MSI writes to external interrupt controller\n * @msi: MSI data\n@@ -104,6 +108,9 @@ struct iproc_pcie {\n \tstruct iproc_pcie_ib ib;\n \tconst struct iproc_pcie_ib_map *ib_map;\n \n+\tbool enable_hotplug;\n+\tbool ep_is_present;\n+\n \tbool need_msi_steer;\n \tstruct iproc_msi *msi;\n };\n", "prefixes": [ "v5", "3/3" ] }