Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp7156703imm; Tue, 24 Jul 2018 09:15:55 -0700 (PDT) X-Google-Smtp-Source: AAOMgpdlB4Rw4+f36MsS3rd73URr2EUy9EAH5XVad2i2nhlg/xi1e0xn1WW2pRQjm583G9ftLDok X-Received: by 2002:a62:8389:: with SMTP id h131-v6mr18295180pfe.105.1532448955101; Tue, 24 Jul 2018 09:15:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1532448955; cv=none; d=google.com; s=arc-20160816; b=RTUBaaoQS4awiXdVhuxzdfVfqYQR/ZOfZpjuHQ5v3xxlHN6N8MTMp8cOfatzYdtW2w 66nZicrRzxdDjDH1kmcZkLO8F7yNppnsdWMZTFcfaVGCrb91YJK0a7BZbBrSp5N7PUEu 695ARm7Se7UoCkOIyh41oIS4kc2sTnlYK7zvMTKLzVSqZlnEAeKh9hhdG+nQ4+4idVXZ 1jJeTaK0G7NlLirCdR71dbeW6Joc8P02hLB8/hFtPo5H5IawdDDwKZrspjlRkFfGekJK IfVv0jzGZg6OyEuFchnGvvGTm1yo8LnH9d67XCOC0SLdwdvXJj/cPf3Pt5EiwBhH5P7P 7bcw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:cc:to:from :subject:arc-authentication-results; bh=kViGTVVykaCtTJioxN0YkM92lxXDgI68fTMycABRIX8=; b=NaOIBLNvzQ0R/jpyqbpZ4uYV9Fro0paUWSvVAKpH6PFuQ4KfC0NYjGXg+velLE+5Q4 KgjqsJNFQllQTGBwofhXhVzWEJOKGLfb+iWPWnGW751rxM9uOXDbfnn5eFepJp/cEfBa oa9oQDciHyfff+kqE1nQ8odozCRzP6rVJ9V0Mybf6qJLiSoL3P45izi/iQdHlZTB4kge OExxBfQJoCtInPSPWyQ7zNwzs2w06sJBBcMcwbDnkG8ExNzVXU79cnV95ADOEyvovk75 WZZnBmesfLNU7JZxaZdZvok9dYS2P1yfgpd8csSmaDlY6YR78ckoEB2XlVeVzHMBGuO3 R+kQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id d2-v6si10758224plh.387.2018.07.24.09.15.40; Tue, 24 Jul 2018 09:15:55 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388589AbeGXRVy (ORCPT + 99 others); Tue, 24 Jul 2018 13:21:54 -0400 Received: from mx1.redhat.com ([209.132.183.28]:58100 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2388334AbeGXRVx (ORCPT ); Tue, 24 Jul 2018 13:21:53 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 697743082152; Tue, 24 Jul 2018 16:14:41 +0000 (UTC) Received: from gimli.home (ovpn-116-105.phx2.redhat.com [10.3.116.105]) by smtp.corp.redhat.com (Postfix) with ESMTP id 60EE05B681; Tue, 24 Jul 2018 16:14:40 +0000 (UTC) Subject: [PATCH v3 2/3] PCI: Samsung SM961/PM961 NVMe disable before FLR quirk From: Alex Williamson To: linux-pci@vger.kernel.org Cc: linux-kernel@vger.kernel.org, linux-nvme@lists.infradead.org Date: Tue, 24 Jul 2018 10:14:40 -0600 Message-ID: <20180724161440.2729.89835.stgit@gimli.home> In-Reply-To: <20180724160440.2729.75178.stgit@gimli.home> References: <20180724160440.2729.75178.stgit@gimli.home> User-Agent: StGit/0.18-102-gdf9f MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 24 Jul 2018 16:14:41 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The Samsung SM961/PM961 (960 EVO) sometimes fails to return from FLR with the PCI config space reading back as -1. A reproducible instance of this behavior is resolved by clearing the enable bit in the NVMe configuration register and waiting for the ready status to clear (disabling the NVMe controller) prior to FLR. Signed-off-by: Alex Williamson --- drivers/pci/quirks.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index e72c8742aafa..3899cdd2514b 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -28,6 +28,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -3669,6 +3670,87 @@ static int reset_chelsio_generic_dev(struct pci_dev *dev, int probe) #define PCI_DEVICE_ID_INTEL_IVB_M_VGA 0x0156 #define PCI_DEVICE_ID_INTEL_IVB_M2_VGA 0x0166 +/* + * The Samsung SM961/PM961 controller can sometimes enter a fatal state after + * FLR where config space reads from the device return -1. We seem to be + * able to avoid this condition if we disable the NVMe controller prior to + * FLR. This quirk is generic for any NVMe class device requiring similar + * assistance to quiesce the device prior to FLR. + * + * NVMe specification: https://nvmexpress.org/resources/specifications/ + * Revision 1.0e: + * Chapter 2: Required and optional PCI config registers + * Chapter 3: NVMe control registers + * Chapter 7.3: Reset behavior + */ +static int nvme_disable_and_flr(struct pci_dev *dev, int probe) +{ + void __iomem *bar; + u16 cmd; + u32 cfg; + + if (dev->class != PCI_CLASS_STORAGE_EXPRESS || + !pcie_has_flr(dev) || !pci_resource_start(dev, 0)) + return -ENOTTY; + + if (probe) + return 0; + + bar = pci_iomap(dev, 0, NVME_REG_CC + sizeof(cfg)); + if (!bar) + return -ENOTTY; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); + + cfg = readl(bar + NVME_REG_CC); + + /* Disable controller if enabled */ + if (cfg & NVME_CC_ENABLE) { + u64 cap = readq(bar + NVME_REG_CAP); + unsigned long timeout; + + /* + * Per nvme_disable_ctrl() skip shutdown notification as it + * could complete commands to the admin queue. We only intend + * to quiesce the device before reset. + */ + cfg &= ~(NVME_CC_SHN_MASK | NVME_CC_ENABLE); + + writel(cfg, bar + NVME_REG_CC); + + /* + * Some controllers require an additional delay here, see + * NVME_QUIRK_DELAY_BEFORE_CHK_RDY. None of those are yet + * supported by this quirk. + */ + + /* Cap register provides max timeout in 500ms increments */ + timeout = ((NVME_CAP_TIMEOUT(cap) + 1) * HZ / 2) + jiffies; + + for (;;) { + u32 status = readl(bar + NVME_REG_CSTS); + + /* Ready status becomes zero on disable complete */ + if (!(status & NVME_CSTS_RDY)) + break; + + msleep(100); + + if (time_after(jiffies, timeout)) { + pci_warn(dev, "Timeout waiting for NVMe ready status to clear after disable\n"); + break; + } + } + } + + pci_iounmap(dev, bar); + + pcie_flr(dev); + + return 0; +} + static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82599_SFP_VF, reset_intel_82599_sfp_virtfn }, @@ -3676,6 +3758,7 @@ static const struct pci_dev_reset_methods pci_dev_reset_methods[] = { reset_ivb_igd }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IVB_M2_VGA, reset_ivb_igd }, + { PCI_VENDOR_ID_SAMSUNG, 0xa804, nvme_disable_and_flr }, { PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, reset_chelsio_generic_dev }, { 0 }