From patchwork Wed May 27 08:01:33 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Robert Richter X-Patchwork-Id: 6488111 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 429D1C0020 for ; Wed, 27 May 2015 08:05:55 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 41C5B206E5 for ; Wed, 27 May 2015 08:05:53 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4113B206CE for ; Wed, 27 May 2015 08:05:52 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YxWJJ-00052c-Ir; Wed, 27 May 2015 08:03:33 +0000 Received: from mail-wi0-x229.google.com ([2a00:1450:400c:c05::229]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1YxWIA-0004L5-2f for linux-arm-kernel@lists.infradead.org; Wed, 27 May 2015 08:02:23 +0000 Received: by wizo1 with SMTP id o1so11784377wiz.1 for ; Wed, 27 May 2015 01:02:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=9yVShRzhU6Ka6sZ0f08onzFoYNr7O4G2gkWxLlcS9dk=; b=uDZayrWovCjWIz92Y3OtYWprWCwlx0qOEc2KtWt7a15PBJggXlVvusHpXYW47Tuicj rIG17X/O3EzfeH6OfSm4ZtIHlTxyEnLow8sg0YkkUApn6ygFeyMmERNcs/qg8mtKKZLs 4bodhv5IoPa+PeraOJo04M5GsLQRzMREjwlV9oT7vk/dHaVk0dWXDE6xydvcnk+HdHuf CEv+o8E+2C0LRpNhL8BCKLQC3MnpYucfAs5X+ZfvkGOhavZDjLZuaYOaKggvDK8kki4j iLAGCkW5kg9XpkiiMnnFce3M1TcDgihBtXh5ngqAR2kd7QgupxgOd7uD73bLLMNmlp8y TCPg== X-Received: by 10.194.52.37 with SMTP id q5mr57594423wjo.122.1432713720163; Wed, 27 May 2015 01:02:00 -0700 (PDT) Received: from rric.localhost (f053086129.adsl.alicedsl.de. [78.53.86.129]) by mx.google.com with ESMTPSA id g11sm25532176wjr.25.2015.05.27.01.01.59 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 27 May 2015 01:01:59 -0700 (PDT) From: Robert Richter To: Tejun Heo Subject: [PATCH v3 3/3] AHCI: Add generic MSI-X interrupt support to SATA PCI driver Date: Wed, 27 May 2015 10:01:33 +0200 Message-Id: <1432713693-4282-4-git-send-email-rric@kernel.org> X-Mailer: git-send-email 2.1.1 In-Reply-To: <1432713693-4282-1-git-send-email-rric@kernel.org> References: <1432713693-4282-1-git-send-email-rric@kernel.org> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150527_010222_310545_F50D6AA5 X-CRM114-Status: GOOD ( 20.66 ) X-Spam-Score: -0.7 (/) Cc: linux-kernel@vger.kernel.org, Robert Richter , linux-ide@vger.kernel.org, Sunil Goutham , Jiang Liu , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Robert Richter This patch adds generic support for MSI-X interrupts to the SATA PCI driver. MSI-X support is needed for host controller that only have MSI-X support implemented, such as the controller on Cavium's ThunderX SoC. Only support for single interrupts is added, multiple per-port MSI-X interrupts are not yet implemented. The new implementation still initializes MSIs first. Only if that fails, the code tries to enable MSI-X. If that fails too, setup is continued with intx interrupts. To not break other chips by this generic code change, there are the following precautions: * Interrupt ranges are not enabled at all. * Only single interrupt mode is enabled for msix cap devices. These devices require a single port only or a total number of int entries less than the total number of ports. In this case only one interrupt will be enabled. * During the discussion with Tejun we agreed to change the init sequence from msix-msi-intx to msi-msix-intx. Thus, if a device offers msi and init does not fail, the msix init code will not be executed. This is equivalent to current code. With this, the code only setups single mode msix as a last resort if msi fails. No interrupt range is enabled at all. Only one interrupt will be enabled. v3: * store irq number in struct ahci_host_priv * change initialization order from msix-msi-intx to msi-msix-intx * improve comments in ahci_init_msix() * improve error message in ahci_init_msix() * do not enable MSI-X if MSI is actively disabled for the device v2: * determine irq vector from pci_dev->msi_list Based on a patch from Sunil Goutham . Signed-off-by: Robert Richter --- drivers/ata/ahci.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 8cdc9ebbbc43..8245f75be6b6 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ enum { AHCI_PCI_BAR_STA2X11 = 0, + AHCI_PCI_BAR_CAVIUM = 0, AHCI_PCI_BAR_ENMOTUS = 2, AHCI_PCI_BAR_STANDARD = 5, }; @@ -499,6 +501,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, + /* Cavium */ + { PCI_DEVICE(0x177d, 0xa01c), .driver_data = board_ahci }, + /* Generic, PCI class code for AHCI */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, @@ -1201,6 +1206,80 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host) {} #endif +static struct msi_desc *msix_get_desc(struct pci_dev *dev, u16 entry) +{ + struct msi_desc *desc; + + list_for_each_entry(desc, &dev->msi_list, list) { + if (desc->msi_attrib.entry_nr == entry) + return desc; + } + + return NULL; +} + +static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports, + struct ahci_host_priv *hpriv) +{ + struct msi_desc *desc; + int rc, nvec; + struct msix_entry entry = {}; + + /* Do not init MSI-X if MSI is disabled for the device */ + if (hpriv->flags & AHCI_HFLAG_NO_MSI) + return -ENODEV; + + nvec = pci_msix_vec_count(pdev); + if (nvec < 0) + return nvec; + + if (!nvec) { + rc = -ENODEV; + goto fail; + } + + /* + * Per-port msix interrupts are not supported. Assume single + * port interrupts for: + * + * n_ports == 1, or + * nvec < n_ports. + * + * We also need to check for n_ports != 0 which is implicitly + * covered here since nvec > 0. + */ + if (n_ports != 1 && nvec >= n_ports) { + rc = -ENOSYS; + goto fail; + } + + /* + * There can exist more than one vector (e.g. for error + * detection or hdd hotplug). Then the first vector is used, + * all others are ignored. Only enable the first entry here + * (entry.entry = 0). + */ + rc = pci_enable_msix_exact(pdev, &entry, 1); + if (rc < 0) + goto fail; + + desc = msix_get_desc(pdev, 0); /* first entry */ + if (!desc) { + rc = -EINVAL; + goto fail; + } + + hpriv->irq = desc->irq; + + return 1; +fail: + dev_err(&pdev->dev, + "failed to enable MSI-X with error %d, # of vectors: %d\n", + rc, nvec); + + return rc; +} + static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, struct ahci_host_priv *hpriv) { @@ -1269,6 +1348,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, if (nvec >= 0) return nvec; + nvec = ahci_init_msix(pdev, n_ports, hpriv); + if (nvec >= 0) + return nvec; + return ahci_init_intx(pdev, n_ports, hpriv); } @@ -1307,11 +1390,13 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev_info(&pdev->dev, "PDC42819 can only drive SATA devices with this driver\n"); - /* Both Connext and Enmotus devices use non-standard BARs */ + /* Some devices use non-standard BARs */ if (pdev->vendor == PCI_VENDOR_ID_STMICRO && pdev->device == 0xCC06) ahci_pci_bar = AHCI_PCI_BAR_STA2X11; else if (pdev->vendor == 0x1c44 && pdev->device == 0x8000) ahci_pci_bar = AHCI_PCI_BAR_ENMOTUS; + else if (pdev->vendor == 0x177d && pdev->device == 0xa01c) + ahci_pci_bar = AHCI_PCI_BAR_CAVIUM; /* * The JMicron chip 361/363 contains one SATA controller and one