From patchwork Thu Apr 22 14:23:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 1469236 X-Patchwork-Delegate: sr@denx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=UTvNqw2a; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4FR05k6ktKz9sVw for ; Fri, 23 Apr 2021 00:23:36 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 3DAFC82B43; Thu, 22 Apr 2021 16:23:22 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.b="UTvNqw2a"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 5DBD282B4A; Thu, 22 Apr 2021 16:23:20 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 55C0F82B11 for ; Thu, 22 Apr 2021 16:23:16 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=kernel.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=pali@kernel.org Received: by mail.kernel.org (Postfix) with ESMTPSA id 43B7E61421; Thu, 22 Apr 2021 14:23:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1619101394; bh=5K9OD9EQPAJ/uAKck/V+e4sFyBdAv9yGWAYl2WM3+v0=; h=From:To:Cc:Subject:Date:From; b=UTvNqw2aF44pkPks3o/Mk95bJRkYVeIzo1dW84V+RzBuDi/GCMuhzOTeJfymHsvgx FDD6UPDteYTs+WE/mz14D+L677Yu09QNbP80AJ0NatS91KG11Z2rrdM7bw1PzFL6mg /MzmRrKYVCxZL8zzIRrvieHhguuEwrLbR3iHPVyQQr4/hdKdkp/v/TEPz8Wlul6APS GSxkeOQc/PcNK0DNNIOW7LCRyA8fPYF7FdeptNl2TOgost4dzxyn/miw+P9MrcCzjn +imjustlktpWLpoelOqC2Q52ShpwQ4N31EZmpichzIuLkBNt5K0hbGpkIcOfKv6Uza IiQTPep6H9lQg== Received: by pali.im (Postfix) id A14937BF; Thu, 22 Apr 2021 16:23:11 +0200 (CEST) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Stefan Roese Cc: Konstantin Porotchkin , =?utf-8?q?Marek_Beh=C3=BAn?= , Remi Pommarel , u-boot@lists.denx.de Subject: [PATCH] arm: a37xx: pci: Fix processing PIO transfers Date: Thu, 22 Apr 2021 16:23:04 +0200 Message-Id: <20210422142304.31065-1-pali@kernel.org> X-Mailer: git-send-email 2.20.1 MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.4 at phobos.denx.de X-Virus-Status: Clean Trying to clear PIO_START register when it is non-zero (which indicates that previous PIO transfer has not finished yet) causes an External Abort with SError 0xbf000002. This bug is currently worked around in TF-A by handling External Aborts in EL3 and ignoring this particular SError. This workaround was also discussed at: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/commit/?id=3c7dcdac5c50 https://lore.kernel.org/linux-pci/20190316161243.29517-1-repk@triplefau.lt/ https://lore.kernel.org/linux-pci/971be151d24312cc533989a64bd454b4@www.loen.fr/ https://review.trustedfirmware.org/c/TF-A/trusted-firmware-a/+/1541 Implement a proper fix to prevent this External Abort. As it is not possible to cancel a pending PIO transfer, simply do not start a new one if previous has not finished yet. In this case return an error to the caller. In most cases this SError happens when there is no PCIe card connected or when PCIe link is down. The reason is that in these cases a PIO transfer takes about 1.44 seconds. For this reason we also increase the wait timeout in pcie_advk_wait_pio() to 1.5 seconds. If PIO read transfer for PCI_VENDOR_ID register times out, or if it isn't possible to read it yet because previous transfer is not finished, return Completion Retry Status value instead of failing, to give the caller a chance to send a new read request. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún Reviewed-by: Stefan Roese --- drivers/pci/pci-aardvark.c | 42 +++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index 3b9309f52c..c43d4f309b 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -132,8 +132,9 @@ PCIE_CONF_FUNC(PCI_FUNC(devfn)) | PCIE_CONF_REG(where)) /* PCIe Retries & Timeout definitions */ -#define MAX_RETRIES 10 -#define PIO_WAIT_TIMEOUT 100 +#define PIO_MAX_RETRIES 1500 +#define PIO_WAIT_TIMEOUT 1000 +#define LINK_MAX_RETRIES 10 #define LINK_WAIT_TIMEOUT 100000 #define CFG_RD_UR_VAL 0xFFFFFFFF @@ -192,7 +193,7 @@ static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno) * * @pcie: The PCI device to access * - * Wait up to 1 micro second for PIO access to be accomplished. + * Wait up to 1.5 seconds for PIO access to be accomplished. * * Return 1 (true) if PIO access is accomplished. * Return 0 (false) if PIO access is timed out. @@ -202,7 +203,7 @@ static int pcie_advk_wait_pio(struct pcie_advk *pcie) uint start, isr; uint count; - for (count = 0; count < MAX_RETRIES; count++) { + for (count = 0; count < PIO_MAX_RETRIES; count++) { start = advk_readl(pcie, PIO_START); isr = advk_readl(pcie, PIO_ISR); if (!start && isr) @@ -214,7 +215,7 @@ static int pcie_advk_wait_pio(struct pcie_advk *pcie) udelay(PIO_WAIT_TIMEOUT); } - dev_err(pcie->dev, "config read/write timed out\n"); + dev_err(pcie->dev, "PIO read/write transfer time out\n"); return 0; } @@ -323,9 +324,14 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, return 0; } - /* Start PIO */ - advk_writel(pcie, 0, PIO_START); - advk_writel(pcie, 1, PIO_ISR); + if (advk_readl(pcie, PIO_START)) { + dev_err(pcie->dev, + "Previous PIO read/write transfer is still running\n"); + if (offset != PCI_VENDOR_ID) + return -EINVAL; + *valuep = CFG_RD_CRS_VAL; + return 0; + } /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); @@ -342,10 +348,15 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, advk_writel(pcie, 0, PIO_ADDR_MS); /* Start the transfer */ + advk_writel(pcie, 1, PIO_ISR); advk_writel(pcie, 1, PIO_START); - if (!pcie_advk_wait_pio(pcie)) - return -EINVAL; + if (!pcie_advk_wait_pio(pcie)) { + if (offset != PCI_VENDOR_ID) + return -EINVAL; + *valuep = CFG_RD_CRS_VAL; + return 0; + } /* Check PIO status and get the read result */ ret = pcie_advk_check_pio_status(pcie, true, ®); @@ -420,9 +431,11 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, return 0; } - /* Start PIO */ - advk_writel(pcie, 0, PIO_START); - advk_writel(pcie, 1, PIO_ISR); + if (advk_readl(pcie, PIO_START)) { + dev_err(pcie->dev, + "Previous PIO read/write transfer is still running\n"); + return -EINVAL; + } /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); @@ -450,6 +463,7 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, dev_dbg(pcie->dev, "\tPIO req. - strb = 0x%02x\n", reg); /* Start the transfer */ + advk_writel(pcie, 1, PIO_ISR); advk_writel(pcie, 1, PIO_START); if (!pcie_advk_wait_pio(pcie)) { @@ -494,7 +508,7 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie) int retries; /* check if the link is up or not */ - for (retries = 0; retries < MAX_RETRIES; retries++) { + for (retries = 0; retries < LINK_MAX_RETRIES; retries++) { if (pcie_advk_link_up(pcie)) { printf("PCIE-%d: Link up\n", pcie->first_busno); return 0;