From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.1 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH, MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 96FADC04AB4 for ; Thu, 16 May 2019 05:54:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6765A2087B for ; Thu, 16 May 2019 05:54:36 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=nvidia.com header.i=@nvidia.com header.b="rOuV7MY9" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726651AbfEPFyf (ORCPT ); Thu, 16 May 2019 01:54:35 -0400 Received: from hqemgate14.nvidia.com ([216.228.121.143]:8984 "EHLO hqemgate14.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726481AbfEPFye (ORCPT ); Thu, 16 May 2019 01:54:34 -0400 Received: from hqpgpgate102.nvidia.com (Not Verified[216.228.121.13]) by hqemgate14.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Wed, 15 May 2019 22:54:39 -0700 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate102.nvidia.com (PGP Universal service); Wed, 15 May 2019 22:54:32 -0700 X-PGP-Universal: processed; by hqpgpgate102.nvidia.com on Wed, 15 May 2019 22:54:32 -0700 Received: from HQMAIL101.nvidia.com (172.20.187.10) by HQMAIL103.nvidia.com (172.20.187.11) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Thu, 16 May 2019 05:54:31 +0000 Received: from manikanta-bm2.nvidia.com (10.124.1.5) by HQMAIL101.nvidia.com (172.20.187.10) with Microsoft SMTP Server id 15.0.1473.3 via Frontend Transport; Thu, 16 May 2019 05:54:29 +0000 From: Manikanta Maddireddy To: , , , , , , CC: , , , Manikanta Maddireddy Subject: [PATCH V4 22/28] PCI: tegra: Access endpoint config only if PCIe link is up Date: Thu, 16 May 2019 11:23:01 +0530 Message-ID: <20190516055307.25737-23-mmaddireddy@nvidia.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190516055307.25737-1-mmaddireddy@nvidia.com> References: <20190516055307.25737-1-mmaddireddy@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 Content-Type: text/plain DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1557986079; bh=k+Iq/+I1e7HquCPLmCBSe50P6YZuE/gWV4V3+GiXdQ0=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:X-NVConfidentiality:MIME-Version: Content-Type; b=rOuV7MY9MZISqXnIQWZ+1DEzjMLBo/ezjHHHZK3p0Es0nVURt72OHuraGJiaXQQgB Tu3IEs4zOOGu1XbthP6bmmg2nD12xg/ifZbgeU8j3hm4LQ9r6mZ8/2fhyIh4IbimZf cZ/ybQ4q8UOZGhuA2IdXjriej4QXRnFMxhUckbXdPJUUmeoxgMr4yWlsjN4tQHXitf E20bc68Wahh+2T/gbTmI9BQEivHLQfDXvVytah7ixkAZKjqx16UyjvfGyFU+N1wAl8 F7PkOm8qE/kTBOFTgPhyCuTQn27sL1vBuAqfgfd8oQopg0Pvr4n7JQbVQuN/GDUwv+ fKOLMmFbZ7PmA== Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org Few endpoints like Wi-Fi supports power on/off and to leverage that root port must support hot-plug and hot-unplug. Tegra PCIe doesn't support hot-plug and hot-unplug, however it supports endpoint power on/off feature as follows, - Power off sequence: - Transition of PCIe link to L2 - Power off endpoint - Leave root port in power up state with the link in L2 - Power on sequence: - Power on endpoint - Apply hot reset to get PCIe link up PCIe client driver stops accessing PCIe endpoint config and BAR registers after endpoint is powered off. However, software applications like x11 server or lspci can access endpoint config registers in which case host controller raises "response decoding" errors. To avoid this scenario, add PCIe link up check in config read and write callback functions before accessing endpoint config registers. Signed-off-by: Manikanta Maddireddy --- V4: No change V3: Update the commit log with explanation for the need of this patch V2: Change tegra_pcie_link_status() to tegra_pcie_link_up() drivers/pci/controller/pci-tegra.c | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/pci/controller/pci-tegra.c b/drivers/pci/controller/pci-tegra.c index d20c88a79e00..33f4dfab9e35 100644 --- a/drivers/pci/controller/pci-tegra.c +++ b/drivers/pci/controller/pci-tegra.c @@ -428,6 +428,14 @@ static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset) return readl(pcie->pads + offset); } +static bool tegra_pcie_link_up(struct tegra_pcie_port *port) +{ + u32 value; + + value = readl(port->base + RP_LINK_CONTROL_STATUS); + return !!(value & RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE); +} + /* * The configuration space mapping on Tegra is somewhat similar to the ECAM * defined by PCIe. However it deviates a bit in how the 4 bits for extended @@ -493,20 +501,50 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { + struct tegra_pcie *pcie = bus->sysdata; + struct pci_dev *bridge; + struct tegra_pcie_port *port; + if (bus->number == 0) return pci_generic_config_read32(bus, devfn, where, size, value); + bridge = pcie_find_root_port(bus->self); + + list_for_each_entry(port, &pcie->ports, list) + if (port->index + 1 == PCI_SLOT(bridge->devfn)) + break; + + /* If there is no link, then there is no device */ + if (!tegra_pcie_link_up(port)) { + *value = 0xffffffff; + return PCIBIOS_DEVICE_NOT_FOUND; + } + return pci_generic_config_read(bus, devfn, where, size, value); } static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) { + struct tegra_pcie *pcie = bus->sysdata; + struct tegra_pcie_port *port; + struct pci_dev *bridge; + if (bus->number == 0) return pci_generic_config_write32(bus, devfn, where, size, value); + bridge = pcie_find_root_port(bus->self); + + list_for_each_entry(port, &pcie->ports, list) + if (port->index + 1 == PCI_SLOT(bridge->devfn)) + break; + + /* If there is no link, then there is no device */ + if (!tegra_pcie_link_up(port)) + return PCIBIOS_DEVICE_NOT_FOUND; + return pci_generic_config_write(bus, devfn, where, size, value); } -- 2.17.1