From patchwork Mon Jul 10 15:52:30 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 9833331 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id B19D660318 for ; Mon, 10 Jul 2017 15:53:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A57AE28608 for ; Mon, 10 Jul 2017 15:53:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 97BA22860D; Mon, 10 Jul 2017 15:53:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 401FD2861D for ; Mon, 10 Jul 2017 15:53:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932067AbdGJPwm (ORCPT ); Mon, 10 Jul 2017 11:52:42 -0400 Received: from foss.arm.com ([217.140.101.70]:37234 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754386AbdGJPwl (ORCPT ); Mon, 10 Jul 2017 11:52:41 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C013F80D; Mon, 10 Jul 2017 08:52:40 -0700 (PDT) Received: from approximate.cambridge.arm.com (approximate.cambridge.arm.com [10.1.207.16]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9C2533F5B0; Mon, 10 Jul 2017 08:52:39 -0700 (PDT) From: Marc Zyngier To: Bjorn Helgaas , Mathias Nyman , Greg Kroah-Hartman Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, Ard Biesheuvel Subject: [PATCH 2/2] usb: host: pci_quirks: Force hard reset of Renesas uPD72020x USB controller Date: Mon, 10 Jul 2017 16:52:30 +0100 Message-Id: <20170710155230.8622-3-marc.zyngier@arm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170710155230.8622-1-marc.zyngier@arm.com> References: <20170710155230.8622-1-marc.zyngier@arm.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The Renesas uPD72020x XHCI controller seems to suffer from a really annoying bug, where it may retain some of its DMA programming across a XHCI reset, and despite the driver correctly programming new DMA addresses. This is visible if the device has been using 64bit DMA addresses, and is then switched to using 32bit DMA addresses. The top 32bits of the address (now zero) are ignored are replaced by the 32bit from the *previous* programming. Sticking with 64bit DMA always works, but doesn't seem very appropriate. A PCI reset of the device restores the normal functionnality, which is done at probe time. Unfortunately, this has to be done before any quirk has been discovered, hence the intrusive nature of the fix. Signed-off-by: Marc Zyngier Acked-by: Mathias Nyman --- drivers/usb/host/pci-quirks.c | 20 ++++++++++++++++++++ drivers/usb/host/pci-quirks.h | 1 + drivers/usb/host/xhci-pci.c | 7 +++++++ 3 files changed, 28 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index a9a1e4c40480..5bed002c7dd3 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -1096,3 +1096,23 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev) } DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff); + +bool usb_xhci_needs_pci_reset(struct pci_dev *pdev) +{ + /* + * Our dear uPD72020{1,2} friend only partially resets when + * asked to via the XHCI interface, and may end-up doing DMA + * at the wrong addresses, as it keeps the top 32bit of some + * addresses from its previous programming under obscure + * circumstances. + * Give it a good wack at probe time. Unfortunately, this + * needs to happen before we've had a chance to discover any + * quirk, or the system will be in a rather bad state. + */ + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + (pdev->device == 0x0014 || pdev->device == 0x0015)) + return true; + + return false; +} +EXPORT_SYMBOL_GPL(usb_xhci_needs_pci_reset); diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index 0222195bd5b0..dcbe4b097b33 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -14,6 +14,7 @@ void usb_amd_quirk_pll_enable(void); void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev); void usb_disable_xhci_ports(struct pci_dev *xhci_pdev); void sb800_prefetch(struct device *dev, int on); +bool usb_xhci_needs_pci_reset(struct pci_dev *pdev); #else struct pci_dev; static inline void usb_amd_quirk_pll_disable(void) {} diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1bcf971141c0..3831705c2817 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -267,6 +267,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) driver = (struct hc_driver *)id->driver_data; + /* For some HW implementation, a XHCI reset is just not enough... */ + if (usb_xhci_needs_pci_reset(dev)) { + dev_info(&dev->dev, "Resetting\n"); + if (pci_reset_function_locked(dev)) + dev_warn(&dev->dev, "Reset failed"); + } + /* Prevent runtime suspending between USB-2 and USB-3 initialization */ pm_runtime_get_noresume(&dev->dev);